ECMA6是什么
它可以理解为是JavaScript的一个标准,实际上JavaScript是ECMA标准的实现和扩展。
ES6即代表ES5.1后的6.0版本,也是泛指5.1之后下一代标准,涵盖了ES2015,ES2016,ES2017等等,而ES2015则是正式名称。
- 开发语言的整体流程

块级作用域
在ES5版本中只存在全局作用域和函数作用域
例如:
var A = 100;//在全局作用域中
function fn(){
//在函数作用域中
var B = 10;
console.log(B);
}
-
ES5和ES6在块级作用域上的对比
效果如下:
//ES5没有块级作用域 if(true){ var v = 100//这是个全局变量 } console.log(v)//100//在ES6中提供了块级作用域,使用let关键字定义块级作用域的变量 if (true) { //块级作用域中定义的变量只能在当前块级作用域中被访问 let v = 100 } console.log(v) //报错v is not defined
let与var的区别
从上面的对比中引出了两个定义变量关键字,一个let,一个var。
- let关键字:允许声明一个作用域被限制在块级中的变量、语句或者表达式。
- 也可以在全局作用域中或函数作用域中定义变量
- var关键字:声明的变量只能是全局的或者是整个函数块的变量。
声名提前现象
-
使用var关键字存在声名提前现象
效果如下:
console.log(a); //undefined var a = 10; //上述代码等价于 var a; //只声名变量,并不初始化-默认值为undefined console.log(a); //undefined a = 10 //初始化变量 赋值 -
let关键字不允许声名提前
效果如下:
//使用let关键字定义变量时,不存在声名提前(变量提升) console.log(a); //报错 Cannot access 'a' before initialization 无法在初始化之前访问“a” let a = 10; //ES6中没有声名提前(变量提升) -
定义变量的关键字还有一个const,只不过是常量,我们试一下const有没有变量提升现象,效果如下:
//const 关键字定义常量时,也是没有声名提前(变量提升) console.log(a); //Cannot access 'a' before initialization const a = 10 -
总结:在使用let以及const声明变量不会提升,所以就会抛错,而使用var声明的变量,会声明提升,所以会打印出undefined
重新声名问题
-
使用var关键字允许重复声明
效果如下:
var a = 100; console.log(a); //100 var a = 1000; console.log(a); //1000 -
使用let关键字不允许重复声明
效果如下:和重复定义常量const报一样的错
let a = 100; console.log(a); //重复声明-抛错-Identifier 'a' has already been declared let a = 1000; console.log(a); const v = 10; //Identifier 'v' has already been declared const v = 20; -
那既然let重复定义和const报一样的错,试试let的重新赋值
let a = 100; console.log(a); //100 a = 1000; console.log(a); //1000
与函数的关系
-
使用var
//使用var 允许声名提前 var v = 100; function fn() { console.log(v); //undefind-这里存在声名提前,所以这里输出v为undefined var v = 1000; console.log(a); //1000 } fn() -
使用let
//使用let来尝试以上代码 let v = 100; function fn() { console.log(v); //Cannot access 'v' before initialization //let在声名变量时将当前环境封闭 //函数作用域封闭-全局作用域中的变量与当前函数作用域无关 let v = 1000; console.log(v); //1000 } fn()
与函数声明
ES5中规定函数声明只能在全局作用域和函数作用域中,不能在块级作用域中声名。
if (true) {
function fn() {
console.log("aaaa");
}
}
fn()
在ES5的标准中,上述代码是报错的,但ES6支持这么写。
if (true) {
//块级作用域
let fn = function () {
console.log("aaaa");
}
}
fn() //fn is not defined 报错证明上面声明的函数是块级作用域中的,外面不可用
对比下面let方式声名,上面的可以理解为是var声名的函数,那么总结为var声名的函数不是块级,可以在全局访问;let声名的函数是块级,不可以在全局访问
变量的解构赋值
ES6中允许按照一定模式从数组或对象中提取值,对变量进行赋值。这种赋值方式被称为“解构赋值”
-
ES5为变量赋值方式如下:
var a = 1; var b = 2; var c = 3; -
ES6为变量赋值方式如下:
let [a,b,c] = [1,2,3]
ES6的解构赋值本质上属于模式匹配。赋值运算符两边的模式相同,左边的变量会被赋予对应位置的值。
解构赋值失败
正确的情况下,变量的索引值对应值的索引值,效果如下:
let [a, b, c] = [1, 2, 3]
console.log(a, b, c);//1 2 3
-
如果左侧变量名多于右侧, 则左侧多的变量赋值不成功为undefined
//如果左侧变量名多于右侧, 则左侧多的变量赋值不成功为undefined let [m, n] = [1] console.log(m, n); //1 undefined -
如果右侧的值多于左侧的变量,那么只匹配对应的值,多余的值则不会解构(不完全解构)
//如果右侧的值多于左侧的变量,那么只匹配对应的值,多余的值则不会解构 let [p, q] = [1, 2, 3] console.log(p, q); //1 2
默认值
解构赋值允许指定默认值
//解构赋值失败时,变量的值是undefined
let [a] = []
console.log(a); //undefined
//默认值-不写的时候当解构赋值失败时,变量为undefined
//默认值-写的时候当解构赋值失败时,变量为事先写的默认值
let [b = 100] = []
console.log(b); //100
let [c = 100] = [1000]
console.log(c); //1000
注意:ES6内部使用全等于来判断变量是否存在值,所以只有当成员的值等于undefined时,默认值才会生效
代码如下:
//ES6底层为变量赋值的值与undefined进行比较(全等于)
let [x = undefined, y = 1] = [2, undefined]
console.log(x, y);
值得注意的是,先赋值后比较,上述例子中由于左边和右边个数相等,所以未结构失败,那么2赋值给了x,undefined赋值给了y,之后进行比较,x是正常的,y==undefined,所以使用了事先设定的默认值
对象的解构赋值
对象的解构赋值是通过变量名与对象的属性名一一对应实现的。
let {
name,
age
} = {
name: "小明",
age: 18
}
console.log(name, age); //小明 18
如果变量名和对象属性名不一样呢?效果如下:
let {
a,
b
} = {
name: "小明",
age: 18
}
console.log(a, b); //undefined undefined
进一步证明了对象赋值是靠变量名和对象的属性名进行对应的
补充:
//对象解构 - 赋值运算符两边格式保持一致
let [x, y] = {
x: 10,
y: 20
}
console.log(x, y); //报错
字符串、数字值和布尔值的解构赋值
字符串的解构赋值
字符串的解构赋值被转换成了类似于数组的对象(不常见)
let [a, b, c, d, e] = "hello"
console.log(a, b, c, d, e); //h e l l o
let [x, y, z] = "xxyyzz"
console.log(x, y, z); //x x y
数值与布尔值的解构赋值
解构赋值时,如果赋值运算符右边是数据或者布尔值的话,则会先转换为对象

//数字值或布尔值的解构赋值-先将数字值或布尔值转换成对象类型
let {
toString: m
} = 100
console.log(m === Number.prototype.toString); //true
let {
toString: x
} = true
console.log(x === Boolean.prototype.toString); //true
函数参数的解构赋值
声名函数时,函数的参数也可以使用解构赋值
function f([a, b]) {
console.log(a, b);
}
f([10, 20]) //10 20
function fn({
m,
n
}) {
console.log(m, n);
}
fn({
m: 10,
n: 20
}) //10 20
//本质上和普通的解构赋值没区别
字符串的扩展
includes()方法
includes()方法用于判断一个字符串是否包含在另一个字符串中,返回布尔值。
注意: includes() 方法区分大小写。
str.includes(searchvalue, position)
- searchvalue:在str字符串中搜索的字符串
- position:可选项,从当前字符串的哪个索引位置开始搜寻子字符串,默认值为0
效果如下:
//includes()方法
var str = "床前明月光疑是地上霜a"
console.log(str.includes("光")); //true
console.log(str.includes("光", 0)); //true
console.log(str.includes("光", 5)); //false
console.log(str.includes("a")); //true
console.log(str.includes("A")); //false
startsWith()方法
startsWith()方法用于判断当前字符串是否以另外一个给定的子字符串“开头”的,返回布尔值。
注意: startsWith() 方法区分大小写。
str.startsWith(searchvalue, position)
- searchvalue:在str字符串中搜索的字符串
- position:可选项,从当前字符串的哪个索引位置开始搜寻子字符串,默认值为0
效果如下:
var str = "床前明月光疑是地上霜a"
//startsWith()方法
console.log(str.startsWith("床")); //true
console.log(str.startsWith("前")); //false
console.log(str.startsWith("光", 4)); //true
endsWith()方法
endsWith()方法用于判断当前字符串是否以另一个给定的字符串结尾的,返回布尔值
注意: endsWith() 方法区分大小写。
str.endsWith(searchvalue, position)
- searchvalue:在str字符串中搜索的字符串
- position:可选项,从当前字符串的哪个索引位置开始搜寻子字符串,默认值为0
效果如下:
var str = "床前明月光疑是地上霜a"
//endsWith()方法
console.log(str.endsWith("a")); //true
console.log(str.endsWith("光", 4)); //false
console.log(str.endsWith("地")); //false
repeat()方法
repeat()方法用于将原有的字符串重复n次,返回一个新字符串。
str.repeat(number)
- number:表示字符串重复的次数
- 如果number参数为小数的话,则会向下取整
- 如果number参数为负数或者无穷大的话,则会报错
- 如果number参数为NaN的话,则为0
- 如果number参数为字符串的话,则会转换为数字值
效果如下:
let str = "x"
//此方法不会影响原来的字符串
console.log(str.repeat(3)); //xxx
console.log(str); //x
console.log(str.repeat(3.6)); //xxx
// console.log(str.repeat(-1));//报错
console.log(str.repeat(NaN));
console.log(str.repeat("3")); //xxx
解构赋值的扩展
解构赋值与深拷贝和浅拷贝
- 深拷贝:修改新变量的值不会影响原有变量的值
- 浅拷贝:修改新变量的值会影响原有的变量的值
效果如下:
//深拷贝:修改新变量的值不会影响原有变量的值
let a = 1;
let b = a;
console.log(a, b); //1 1
b = 2;
console.log(a, b); //1 2
//浅拷贝:修改新变量的值会影响原有的变量的值
let x = {
name: "小明"
};
let y = x;
console.log(x);
y.name = "张三";
console.log(x)
此时x的数据被y改变,发生了浅拷贝,因为他们引用的是同一个地址,浅拷贝的时候没有给y开辟新的内存空间,只是把x指向数据的指针拷贝了y。
那么利用解构赋值来实现上面的例子,效果如下:
const a = {
name: "name",
age: 18,
marriage: false,
}
let {
name,
age,
marriage
} = a;
console.log(a); //{ name: 'name', age: 18, marriage: false }
name = "name1";
age = 20;
marriage = true;
console.log(a) //{ name: 'name', age: 18, marriage: false }
此时a数据并没有因为变量的改变发生改变,解构赋值貌似是深拷贝啊??
继续改一下,效果如下:
const a = {
name: "name",
age: 18,
marriage: false,
addr: {
province: "sichuan",
city: "chengdu"
}
}
let {
name,
age,
marriage,
addr
} = a
name = "myname"
age = 26
marriage = true
addr.province = "shanghai"
addr.city = "shanghai"
console.log(name, age, marriage, addr)
console.log(a)
此时发现解构赋值出来的对象将原来对象的add的数据修改了,这样看还是浅拷贝
总结:总结:解构赋值,如果所解构的原对象是一维数组或对象,其本质就是对基本数据类型进行等号赋值,那它就是深拷贝;如果是多维数组或对象,其本质就是对引用类型数据进项等号赋值,那它就是浅拷贝;
模板字符串
模板字符串是增强版的字符串,使用反引号(``)来代替普通字符串中的用双引号和单引号。它可以当做普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
//普通字符串
console.log(`窗前明月光,疑是地上霜`);
//多行字符串
console.log(`
窗前明月光
疑是地上霜
举头望明月
低头思故乡`);
//在字符串中嵌入变量
let name = "李白"
console.log(`${name},床前明月光。。。`);
带标签的模板字符串
模板字符串的功能可以紧跟在一个函数后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能
//带标签的模板字符串
console.log("aaaa"); //aaaa
console.log `aaaa` //[ 'aaaa' ]
标签模板其实不是模板,而是函数调用的一种特殊形式,“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数
原始字符串
在标签函数的第一个参数中,存在一个特殊的属性raw,可以通过它来访问模板字符串的原始字符串,而不经过特殊字符的替换。
//原始字符串
let str = "参数"
function fn(arg) {
console.log(arg.raw[0]);
}
fn `我是参数` //我是参数 原版的,被定义时的
fn `我是${str}` //我是 处理的,处理之后的
所谓的原始字符串就是模板字符串被定义时的内容,而不是处理之后的内容
数组的扩展
扩展运算符
扩展运算符(…)允许一个表达式在原地展开,当需要多个参数时(比如函数调用时)或多个值(比如字面数组)
例如:
//扩展运算符
//定义一个数组,将数组中的每一项打印出来
var arr = [1, 2, 3]
console.log(arr); //[ 1, 2, 3 ]
console.log(...arr); //1 2 3
还可以用来对数组一些操作,效果如下:
-
复制数组
var arr2 = [...arr1] console.log(arr2); arr2[2] = 10 console.log(arr1, arr2); //[ 1, 2, 3, 4, 5 ] [ 1, 2, 10, 4, 5 ] 不变为深复制 -
合并数组
//ES5合并数组的方法 arr3 = [9, 8, 7] console.log(arr3.concat(arr1)); //例如扩展运算符合并 console.log([...arr1, ...arr3]); -
与解构赋值配合
let arr = [1, 2, 3, 4, 5] //ES5的方法 // let v = arr[0] // var list = arr.slice(1) // console.log(v, list); //1 [ 2, 3, 4, 5 ] //ES6 let [v, ...list] = arr console.log(v, list); //1 [ 2, 3, 4, 5 ]注意:解构赋值中的...扩展运算符只能放在最后面 -
与对象配合使用
注意:扩展运算符必须与可迭代的对象配合使用//注意:扩展运算符必须与可迭代的对象配合使用 var obj = { name: "小红", age: 18 } console.log({ ...obj });
Array提供的方法
Array.from()方法
Array.from()方法用于从一个类似数组或可迭代对象中创建一个新的数组实例
//构建一个类数组对象
//1.可迭代
//2.有效的length
var obj = {
0: "小明",
1: "小红",
2: "小刚",
3: "小白",
length: 4
}
// console.log(obj);
for (var i = 0; i < obj.length; i++) {
console.log(obj[i]);
}
//ES6的from方法根据一个类数组对象创建一个真的数组
console.log(Array.from(obj)); //[ '小明', '小红', '小刚', '小白' ]
值得注意的是扩展运算符...也可以将某些数据结构转为数组
var obj = {
0: "小明",
1: "小红",
2: "小刚",
3: "小白",
length: 4
}
function fn() {
//arguments对象 用于接收函数的参数
console.log(...arguments);
}
fn(1, 2, 3)
Array.of()方法
Array.of()方法用于创建一个具有可变数量参数的新数组实例,而不考虑参数的类型或类型
//Array.of() 如果传递一个参数时,表示一个元素内容
console.log(Array.of(5)); //[ 5 ]
console.log(Array.of(1, 2, 3)); //[ 1, 2, 3 ]
console.log(new Array(1, 2, 3)); //[ 1, 2, 3 ]
//new Array() 如果传递一个参数时,表示length
console.log(new Array(5)); //[ <5 empty items> ]
console.log(Array.of()); //[]
这个方法的主要目的,是弥补数组构造函数Array()的不足,因为参数个数的不同,会导致Array()的行为有异常
值得注意的是:Array.of()如果不传递任何参数,则返回一个空数组
Array对象提供的方法
copyWitchin()方法
copyWitchin()方法用于浅复制数组的一部分到同一数组的另一个位置,并返回他,而不修改其大小
arr.copyWithin(target, start, end)
- target:0为基底的索引,复制序列到该位置。如果是负数,taiget将从尾端开始计算
- start:0为基底的索引,开始复制元素的起始位置。如果是负数,start将从末尾开始计算
- end:0为基底的索引,开始复制元素的结束位置。copyWithin()方法将会拷贝到该位置,但不包括end这个位置的元素。如果是负数,end将从末尾开始计算
let arr = [1, 2, 3, 4, 5];
console.log(arr.copyWithin(1, 3));
console.log(arr.copyWithin(2));
/**
* copyWitchin()方法
* 参数:
* target:该参数的最大值等于当前数组的length属性值-1
* start:
* end:表示当前截取结束的索引值(不包含当前索引值的元素)
* 如果当前参数值不写,自动截取到数组的最后
* 作用:检索指定数组中从start到end区间的元素,复制到当前数组中的指定索引值
* 注意:该方法不能改变数组的长度
* 修改了原有数组
*/
find()与findindex()方法
-
find()方法返回数组中满足提供的测试函数的第一个元素的值,否则返回undefined
arr.find(callback,thisArg)参数:
- callback:在数组每一项上执行的函数,该函数接收三个参数
- element:当前遍历的元素
- index:当前遍历的索引值
- array:数组本身
- thisArg:可选,指定callback的this参数
let arr = [1, 2, 3, 4, 5] var result = arr.find(function (element, index, array) { // console.log(element, index, array); return element > 1 }) console.log(result); /** * 1 0[1, 2, 3, 4, 5] 2 1[1, 2, 3, 4, 5] 3 2[1, 2, 3, 4, 5] 4 3[1, 2, 3, 4, 5] 5 4[1, 2, 3, 4, 5] finc(callback)特点 返回find()方法的回调函数中符合条件的第一个元素的值 参数: callback:调用find时的回调函数 element:指定数组中每一项元素的值 index:所对应元素的索引值 array:数组本身 当数组调用方法时,将指定数组进行遍历 */ - callback:在数组每一项上执行的函数,该函数接收三个参数
-
findindex()方法返回数组中满足提供的测试函数的第一个元素的索引值,否则返回-1
arr.findindex(callback,thisArg)参数:
- callback:在数组每一项上执行的函数,该函数接收三个参数
- element:当前遍历的元素
- index:当前遍历的索引值
- array:数组本身
- thisArg:可选,指定callback的this参数
- callback:在数组每一项上执行的函数,该函数接收三个参数
let arr = [1, 2, 3, 4, 5]
var result = arr.findIndex(function (element, index, array) {
// console.log(element, index, array);
return element > 3
})
console.log(result);
fill()方法
fill()方法用一个固定值填充一个数组中从起始索引到终止索引的全部元素,不包括终止索引值
arr.fill(value,start,end)
- value:用来填充数组元素的值
- start:可选项,起始索引,默认值为0
- end,可选项,终止索引,默认值为this.length
- 返回值:修改后的数组
let arr = [1, 2, 3, 4, 5]
var result = arr.fill(6)
console.log(result, arr);//不写起始和终止的话,会默认替换全部
console.log(arr.fill(2,1,3));
includes()方法
includes()方法用于判断一个数组是否包含一个指定的值。根据情况,如果包含则返回true,否则返回false
arr.includes(searchElement,fromindex)
- searchElement:需要查找的元素值
- fromindex:可选项:从该索引出开始查找searchElement。如果为负值,则按升序从array.length-fromindex的索引开始搜索,默认为0
let arr = [1, 2, 3, 4, 5]
console.log(arr.includes(2, 2)); //从索引值2开始向后查找,查找2,没找到返回false
函数的扩展
函数参数的默认值
ES5的标准中不允许对函数的参数设置默认值的,ES6的标准新增了对函数的参数设置其默认值的内容
function fn(arg = 10) {
console.log(arg);
}
fn() //当不传递参数时,函数会默认使用事先设置的默认值
fn(100) //传递实参时,默认的形参没作用
函数参数的作用域
如果为函数的参数设置默认值的话,当函数声明进行初始化时,参数会形成一个独立的作用域,这个作用域会在函数初始化完毕时消失
let v = 100;
function fn(arg = v) {
let v = 1000
console.log(arg)
}
fn() //100
当加载当前函数的形参,并且设置其默认值时,形成一个独立的作用,当前作用域既不是全局作用域,也不是函数作用域,更不是块级作用域
当为参数设置默认值时,当前只能访问全局变量
rest参数
ES6新增了rest参数(…变量名),用于获取函数多余的参数,替代arguments对象。与rest参数配合的变量是一个数组,该变量将多余的参数放入数组中。
//ES5接收多余的参数,接收多余的实参
function f(a, b) {
console.log(a, b, arguments[2]);
}
f(1, 2, 3)
//Es6-利用rest参数接收多余的实参
function fn(a, b, ...args) {
console.log(a, b, args);
}
fn(1, 2, 3, 4, 5) //1 2 [ 3, 4, 5 ]
注意:
- rest参数之后不能再有其他参数,否则会报错
- 函数的length属性,不包含rest参数
箭头函数
ES6新增了箭头函数,相比函数表达式具有较短的语法并于词法的方式绑定this,箭头函数总是匿名的
var n = () => {
console.log("我是函数");
}
n()
语法结构:
():表示声名函数时的函数体
=>内容:表示声名函数时的函数体
箭头函数的注意事项
使用箭头函数时,需要注意以下几点:
-
函数体内的this,就是定义时所在的对象,而不是使用时所在的对象
function foo(){ setTimeout(()=>{ console.log('id',this.id); },100) } var id = 21 foo.call({id:42})//42 -
不可以当构造函数,也就是说不可以使用new命令,否则会报错
-
不可以使用arguments对象,该对象在函数体内不存在,可以使用rest参数实现其功能
对象的扩展
对象的属性
ES6 允许将变量名和函数名直接作为对象的属性和方法的方式,如下:
let name = "小明"
function sayMe() {
console.log("我是小明")
}
//ES5
// var obj = {
// name: name, //第二个name 表示变量名
// sayMe: sayMe //第二个sayMe 表示函数名
// }
// console.log(obj.name);
//ES6 允许将变量名和函数名直接作为对象的属性和方法的方式
var obj = {
name,
sayMe
}
console.log(obj.name);
Object.is()方法
ES5中比较两个值是否相等,使用的是相等运算符和全等运算符=,但这两个运算符在使用时都有缺点:
- 相等运算符在比较值钱,会自动转换数据类型
- 全等运算符导致NaN与自身不等,+0等-0等问题
ES6提出了等值算法来解决以上问题,Object.is()方法就是对同值相等算法的具体实现
效果如下:
//ES5的缺点
console.log(+0 === -0); //true
console.log(NaN == NaN); //false
//ES6
console.log(Object.is(+0, -0)); //false
console.log(Object.is(NaN, NaN)); //true
Object.assign()方法
Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象
Object.assign(target,...sources)
- target:目标对象
- sources:源对象
- 返回值:目标对象
var obj = {
name: "小明",
age: 18
}
var target = {}
var result = Object.assign(target, obj)
console.log(result, target); //{ name: '小明', age: 18 } { name: '小明', age: 18 }
target.name = "小红"
console.log(obj, target); //{ name: '小红', age: 18 } { name: '小红', age: 18 }
//证明这个函数是浅复制
super关键字
ES6新增了super关键字用于指向当前对象的原型对象
var pro = {
age: 18
}
var obj = {
name: "小明",
age: 25,
sayMe() {
console.log(super.age, this.age);
}
}
Object.setPrototypeOf(obj, pro)
// console.log(obj.name, obj.age);
obj.sayMe()
本文详细介绍了ES6的新特性,包括块级作用域、let与var的区别、变量的解构赋值以及字符串、数组和函数的扩展。通过实例解析了let的声明提前、重复声明问题,以及解构赋值在数组和对象中的应用。此外,还探讨了字符串的includes(), startsWith(), endsWith()方法以及函数参数的默认值等功能。"
111731205,10295783,使用PyQt5构建PDF阅读器:添加翻页与缩放功能,"['Python GUI', 'PDF处理', 'PyQt5应用']
2253

被折叠的 条评论
为什么被折叠?



