ES6语法总结
一、为什么使用ES6
变量提升特性增加了程序运行时的不可预测性
语法过于松散,实现相同的功能,不同的人可能会写出不同的代码
没有块级作用域的缺点:
1、内层变量可能会覆盖外层变量
2、用来计数的循环变量泄露为全局变量
二、let和const命令
1、let
ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
let的特点
没有变量的提升
有块级作用域
不能重复声明
可以重复赋值
2、暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
上面代码中,在let命令声明变量tmp之前,都属于变量tmp的“死区”。
“暂时性死区”也意味着typeof不再是一个百分之百安全的操作。
typeof x; // ReferenceError
let x;
上面代码中,变量x使用let命令声明,所以在声明之前,都属于x的“死区”,只要用到该变量就会报错。因此,typeof运行时就会抛出一个ReferenceError。
作为比较,如果一个变量根本没有被声明,使用typeof反而不会报错。
typeof undeclared_variable // "undefined"
上面代码中,undeclared_variable是一个不存在的变量名,结果返“undefined”。所以,在没有let之前,typeof运算符是百分之百安全的,永远不会报错。现在这一点不成立了。这样的设计是为了让大家养成良好的编程习惯,变量一定要在声明之后使用,否则就报错。
3、const命令
const声明一个只读的常量
没有变量的提升
有块级作用域
不能重复声明
声明时必须赋初始值
对于数组和对象的元素修改,不算作对常量的修改(地址没有发生改变)
一般常量使用大写(默认)
三、解构赋值
1、数组的解构赋值
1、基本用法
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
以前,为变量赋值,只能直接指定值。
let a = 1;
let b = 2;
let c = 3;
ES6 允许写成下面这样。
let [a, b, c] = [1, 2, 3];
上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
如果解构不成功,变量的值就等于undefined。
let [foo] = [];
let [bar, foo] = [1];
以上两种情况都属于解构不成功,foo的值都会等于undefined。
另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
let [x, y] = [1, 2, 3];
x // 1
y // 2
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
上面两个例子,都属于不完全解构,但是可以成功。
2、默认值
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
3、交换变量值
let a = 56;
let b = 98;
[b, a] = [a, b];
console.log("a", a); // 98
console.log('b', b); // 56
4、 展开
let arr = [1, 2, 3, 5];
let [a, ...b] = arr;
console.log(a); 1
console.log(b); [2,3,5]
5、字符串
[a,b]='你好吗?'
console。log(b) //好
6、忽略
[a, , ,b]=[1,2,3,4]
console.log(b) // 4
2、对象的解构赋值
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
三、String的扩展方法
startsWith()
表示参数字符串是否在原字符串的头部,返回布尔值
endsWith()
表示参数字符串是否在原字符串的尾部,返回布尔值
repeat( )
repeat方法表示将原字符串重复n次,返回一个新字符串。
raw()
返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。
includes()
返回布尔值,表示是否找到了参数字符串。
trim( )
去除空格
trimLeft()去除左边空格
trimRight( )去除右边空格
for of 循环
padStart( )
padStart()方法在原字符串开头补全指定的补全字符串,直到目标长度所形成的新字符串。
padEnd( )
padEnd()方法在原字符串末尾补全指定的补全字符串,直到目标长度所形成的新字符串。
四、对象的扩展
1、属性的简洁表示法
let name = '小明';
let age = 18;
let obj = {
name,
age,
say() { // function可省略
console.log('我的名字是', this.name, '我今年' + this.age + '岁了');
}
}
2、对象的动态属性
var key = window.prompt("请输入对象名称","like");
var value = window.prompt("请输入对象值","好好学习");
var obj = {[key+"web"]:value};
console.log(obj);//likeweb: "好好学习"
3、对象的继承
let name = '小明';
let age = 20;
let obj = {
name,
age,
say() {
console.log(`我是${this.name},我今年${this.age}岁了`);
}
}
let user = {
__proto__: obj,
}
user.say();//我是小明,我今年20岁了