深入理解ES6
目录
8 迭代器(Iterator)和生成器(Generator)
1 块级作用域绑定
1.1 var声明及变量提升机制
在函数作用域或全局作用域中通过var声明的变量,无论实际上在哪里声明的,都会被当作当前作用域顶部声明的变量,这就是我们常说的提升(Hoisting)机制。
function getValue(cond){
if(cond){
var value = "blue";
return value;
}else{
//此处value的值为undefined
return null
}
//此处value的值为undefined
}
//预编译代码如下
function getValue(cond){
var value
if(cond){
value = "blue";
return value;
}else{
return null
}
}
1.2 块级声明
-
let声明
-
禁止重声明
-
const声明
-
零时死区
1.3 循环中的块作用域绑定
-
循环中的函数
-
循环中的let声明
-
循环中的const声明
1.4 全局作用域绑定
1.5 快级绑定最佳实践的进化
2 字符串和正则表达式
2.1 更好的Unicode支持
- UTF-16码位
- codePointAt()方法
- String.fromCodePoint()方法
- normalize()方法
- 正则表达式u修饰符
2.2 其他字符串变更
- 字符串中的子串识别
- repeat方法
2.3 其他正则表达式语法变更
- 正则表达式y修饰符
- 正则表达式的复制
- flags属性
2.4 模板字面量
- 基础语法
- 多行字符串
- 字符串占位符
- 标签模板
3 函数
3.1 函数形参的默认值
3.2 处理无命名参数
3.3 增强的Function构造函数
3.4 展开运算符
3.5 name属性
3.6 明确函数的多重用途
3.7 快级函数
3.8 箭头函数
3.9 尾调用优化
4 扩展对象的功能性
4.1 对象类别
4.2 对象字面量语法扩展
4.3 新增方法
4.4 重复的对象字面量属性
4.5 自由属性枚举顺序
4.6 增强对象原型
4.7 正式的方法定义
5 解构:使数据访问更便捷
5.1 为何使用解构功能
在ES5及早期版本中开发者为了从数组和对象中获取特定的数据并赋值给变量,编写了许多看起来同质化的代码。就像这样,从person对象中提取name和age的值并存储为同名的局部变量。
let person= {
name:"lisi",
age:19
}
let name = person.name
let age = person.age
这种方法有许多缺陷,如果要提取更多的变量,则必须要依次编写类似的代码。如果其中还嵌套结构,只靠遍历是找不到真实的信息的。必须要深入挖掘整个数据结构才能找到所需的数据。所以ES6为对象和数组添加了解构功能,将数据结构打散的过程变得更加简单,可以从打散后的更小部分获取所需的信息。
5.2 对象解构
let person= {
name:"lisi",
age:19
}
let {name,age} = person
这段代码和上面的结果一样。person.name的值被存在名为name的变量中,person.age的值被存在名为age的变量中。name、age变量的名称是person的属性名称,这里必须保持一直。
-
5.2.1 解构赋值
上面的例子是将对象的解构应用到变量的声明中。同样可以在给变量赋值的时候使用解构语法。
let person= {
name:"lisi",
age:19
}
let name = 'liwu'
let age = 22
({name,age} = person)
注意一定要用一对小括号包裹结构赋值语句。JavaScript引擎将一对开放的花括号视为一个代码块,而语法规定,代码块语句不允许出现在赋值语句的左侧,添加小括号就可以将块语句转化为一个表达式,从而实现整个解构赋值的过程。
-
5.2.2 默认值
let person= {
name:"lisi",
age:19
}
let {name,age,height} = person
console.log(height) // undefined
当定义的变量名称在对象中没有对应的属性的时候,就会给它赋值为undefined。这时候我们可以为它定义一个默认值,在属性的后面添加= 值 即可。如果对象中已经有值了,则再为它设置默认值则没有效果,因为已经有值了,设置的默认就不会生效。
let person= {
name:"lisi",
age:19
}
let {name,age,height=180} = person
console.log(height) // 180
-
5.2.3 为非同名局部变量赋值
上面的实例中,解构赋值使用的都是与对象属性同名的局部变量,如person.name的值被存储在变量name中。如果使用不同的名称,需要在名称后面加一个分号 :anothername。 设置默认值的时候也可以使用不同名称,如heigth:hi = 180,好像意义不大啊,既然对象中没有该属性,直接hi=180好了。
let person= {
name:"lisi",
age:19
}
let {name:firstname,age,height:hi=180} = person
console.log(firstname) //lisi
console.log(hi) //180
-
5.2.4嵌套对象解构
let node = {
type:"Identifier",
name:"foo",
loc:{
start:{
line:1,
colunm:2
},
end:{
line:3,
colunm:4
}
}
};
let {loc:{start}} = node; //{line: 1, colunm: 2}
对象中包含对象,解构的时候就也需要嵌套。
5.3 数组解构
与对象解构相比数组解构简单了许多。它使用的数组字面量。且解构操作全部在数组内部完成。
let arr1 = ['a','b','c','d','e','f'];
let [a1,b1] = arr1;
console.log(a1) //a
console.log(b1) //b
let [,,,d1] = arr1
console.log(d1) //d
数组的解构是按照顺序解构的,如果希望跳过前面的值,则需要用占位符,用逗号,,,隔开就可以。后面的元素会忽略。
-
5.3.1 解构赋值
数组的解构也可以用于赋值,但是不像对象一样需要使用小括号括起来。
let arr1 = ['a','b','c','d','e','f'];
let a1='aa',b1='bb';
console.log(a1,b1); //aa bb
[a1,b1] = arr1;
console.log(a1,b1); //a b
数组的解构语法还有一个独特的用例:交换两个变量的值。在es5中交换两个值,通常需要引入第三个零时变量。在es6中,使用数组解构的方法。等号左边 是一个解构模式[],右侧是一个为了交换过程创建的临时数组字面量。代码执行过程先解构临时数组,将d和c的值复制到左边解构式中的前两个位置,最终的结果是交换了它们的值。
let a=11,b=12,temp;
temp = a;
a = b;
b = temp;
// a=12 b=11 temp=11
let c=11,d=12;
[c,d] = [d,c];
//c=12 d=11
-
5.3.2 默认值
let color = ['red','green'];
let [firstColor,secondColor,threeColor] = color; //threeColor = undefined
let [fColor,sColor,tColor="yellow"] = color; //tColor = yellow
当指定的属性不存在或者其值为undefined的时候使用默认值。
-
5.3.3嵌套数组解构
let color = ['red',['green',"blue"],"yellow"];
let [fColor,[sColor]] = color
-
5.3.4不定元素
在数组中可以通过...语法将数组中的其余元素赋值给一个指定的变量。如下面代码所示。
let color = ['red','green','blue','yellow'];
let [fColor,...lColor] = color;
console.log(lColor) //["green", "blue", "yellow"]
该方法可以用于数组的克隆。JavaScript在设计的时候没有数组克隆的功能,在es5中可以使用concat()方法来克隆数组。concat()设计的初衷是连接两个数组,如果调用时不传入参数就会返回当前数组的副本。在es6中我们可以通过不定元素来实现相同的功能。
let color = ['red','green','blue','yellow'];
let c1 = color.concat();
let [...c2] = color;
代码中c1和c2是同color一样的数组,会占用不同的内存空间。数组是引用型变量,如果使用let c3 = color的话,c3会和color公用一个内存空间,不属于克隆。
在被解构的数组中,不定元素必须为最后一个条目,在后面继续添加逗号会导致程序抛出语法错误。
5.4 混合解构
let node = {
type:"Identifier",
name:"foo",
loc:{
start:{
line:1,
colunm:2
},
end:{
line:3,
colunm:4
}
},
range:[5,6]
};
let {loc:{start},range:[startIndex]} = node; //{line: 1, colunm: 2} 5
同时使用对象和数组来解构,这样你就可以从任何混杂着对象和数组的数据解构中提取你想要的数据了。
5.5解构参数
-
5.5.1必须传值的解构参数
解构可以用在函数参数的传递过程中。当定义一个接收大量可选参数的函数时,我们通常会创建一个可选对象,将额外的参数定义为这个对象的属性。
function setCookie(name,value,options){
options = options || {};
let secure = options.secure,
path = options.path,
domain = options.domain,
expires = options.expires;
// 设置cookie代码
}
setCookie("tpye","js",{secure:true,expires:60000});
// 使用解构的方式重写上面代码
function setCookie(name,value,{secure,path,domain,expires}){
// 设置cookie代码
}
setCookie("tpye","js",{secure:true,expires:60000});
解构参数有一个奇怪的地方,默认情况下,如果调用的函数不提供被解构的参数会导致程序抛出错误。举个例子,上面的代码中setCookie()函数如果不传递第三个参数,就会报错。
setCookie("type","js");//程序错误
缺失的第三个参数,其值为undefined。当调用setcookie函数的时候,JavaScript引擎实际上做了这些事情。
function setCookie(name,value, options){
let {secure,path,domain,expires} = options;
// 设置cookie代码
}
如果解构赋值表达式的右值为null或undefined,则程序会报错。同理,若在调用setCookie()函数时不传入第三个参数,也会导致程序报错。
如果解构参数是必须的,大可忽略这些问题,但是如果希望将解构参数定义为可选,那么就必须为其提供默认值来解决这个问题:
function setCookie(name,value,{secure,path,domain,expires} = {}){
// 设置cookie代码
}
-
5.5.2解构参数的默认值
可以为解构参数指定默认值,
function setCookie(name, value,
{ secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
}
) {
// 设置cookie代码
}
在这段代码中,解构参数的每一个属性都有默认值。然而这个方法也有许多缺点:首先,函数声明变得比以前更加复杂;其次,如果解构参数是可选的,那么仍然要给它添加一个空对象作为参数。否则setCookie("type","js")这样的调用,程序依然会报错。这里建议对于对象类型的解构参数,为其赋予相同的解构默认参数:
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
}
) {
// 设置cookie代码
}
现在函数变得完整了,第一个对象字面量是解构参数,第二个为默认值。但是这样会造成很多代码冗余。你可以将默认值提取到一个独立的对象中,从而消除冗余。
const setCookiedefaults = {
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
}
function setCookie(name, value,
{
secure = setCookiedefaults.secure,
path = setCookiedefaults.path,
domain = setCookiedefaults.domain,
expires = setCookiedefaults.expires
} = setCookiedefaults
) {
// 设置cookie代码
}
使用解构参数后,不得不面对处理默认参数的复杂逻辑,但它也有好的一面,如果要改变默认值,可以立即在setCookiedefaults中修改,改变的值将自动同步到所有出现的地方。
6 Symbol和Symbol属性
7 Set集合与Map集合
8 迭代器(Iterator)和生成器(Generator)
9 JavaScript中的类
10 改进数组的功能
11 Promise与异步编程
12 代理(Proxy)和反射(Peflection)
13 用模块封装代码