主要列举了工作开发中一些高频使用的 ECMAScript 6 的实用内容。
参考:《ECMAScript 6 入门》
1. let 和 const
let
,const
声明的变量只在它所在的代码块有效。
1.1. var
存在的问题
var
有作用域问题(会污染全局作用域)var
可以重复声明var
会变量提升预解释var
不能定义常量
1.2. let
、const
特性
let
、const
不可以重复声明let
、const
不存在变量提升let
、const
不会声明到全局作用域上let
、const
存在暂时性死区(temporal dead zone,简称 TDZ)。let
和const
声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,会导致报错。const
做常量声明(一般常量名用大写),const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
1.3. 代码说明
1.3.1. 作用域
var
有作用域问题(会污染全局作用域),而 let
、const
不会;var
在顶层作用域声明的变量,会直接挂在全局 window
对象下,成为 window
对象的一个属性。1
2
3
4
5
6
7// var
var a = 1;
console.log(window.a);
// let、const
let a = 1;
console.log(window.a); // undefined
1.3.2. 重复声明
var
可以重复声明同一个变量,但 let
、const
不行;let
、const
不允许在相同作用域内,重复声明同一个变量。1
2
3
4
5
6
7// var
var a = 1;
var a = 2;
// let、const
let a = 1;
let a = 2; // Uncaught SyntaxError: Identifier 'a' has already been declared
1.3.3. 变量提升、暂时性死区
var
存在变量提升、而 let
、const
不存在,且 let
、const
存在“暂时性死区”。1
2
3
4
5
6
7
8
9
10
11
12
13
14// var
console.log(a); // undefined
var a = 5;
// let、const
console.log(a); // Uncaught ReferenceError: a is not defined
let a = 5;
// 暂时性死区
var a = 5;
{
console.log(a); // Uncaught ReferenceError: a is not defined
let a = 4;
}
1.3.4. 常量
var
不能直接定义常量,而 const
可以定义常量。1
2const a = 5;
a = 6; // Uncaught TypeError: Assignment to constant variable
2. 解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。本质上,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
数组,对象,字符串,数字和布尔值都能进行结构,但常用的还是对数组和对象进行结构。
2.1. 数组的解构赋值
事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。如果等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错。
1 | // 1. 通常情况 |
2.2. 对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
1 | // 1. 通常情况 |
2.3. 字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。1
2const [a, b, c, d, e, length] = 'hello';
// a: "h" .... length: 5
3. 箭头函数
3.1. 什么是箭头函数
3.1.1. 箭头函数简介
箭头函数的语法非常简单 (parameters) => { statements }
,箭头函数只能用赋值式写法,不能用声明式写法。看一下最简单的箭头函数表示法:1
2let sayHello = () => { console.log('Hello World'); }
sayHello(); // Hello World
3.1.2. 箭头函数的优点
和普通函数相比,箭头函数主要就是以下两个方面的特点:
- 更简化的代码语法
- 没有局部 this 的绑定
- 不绑定 arguments
3.2. 更简化的代码语法
3.2.1. 一般写法
(parameters) => { statements }
1
2
3
4
5
6
7
8
9
10
11
12// 求两个数的和并在控制台输出
// ES6
let sum = (a, b) => {
console.log(a + b);
return a + b;
}
// ES5
var sum = function(a, b) {
console.log(a + b);
return a + b;
};
3.2.2. 省略 () 的情况
如果只有一个参数,可以省略()
括号。parameters => { statements }
1
2
3
4
5
6
7
8
9
10
11
12// 求一个数的两倍,并输出
// ES6
let double = num => {
console.log(num * 2);
return num * 2;
}
// ES5
var double = function(num) {
console.log(num * 2);
return num * 2;
};
3.2.3. 省略 {} 的情况
如果返回值仅仅只有一个表达式(expression), 还可以省略大括号{}
。parameters => statements
1
2
3
4
5
6
7
8// 求一个数的两倍
// ES6
let double = num => num * 2;
// ES5
var double = function(num) {
return num * 2;
};
3.2.4. 特殊情况
如果箭头函数直接返回一个对象,必须在对象外面加上括号。1
2
3
4
5
6
7
8
9
10// ES6
let returnObj = () => ({name: "xiguapi", age: 23});
// ES5
var returnObj = function() {
return {
name: "xiguapi",
age: 23
}
};
3.3. 没有局部 this 的绑定
和一般的函数不同,箭头函数不会绑定 this
。 或则说箭头函数不会改变 this
本来的绑定。
我们用一个例子来说明:1
2
3
4function Counter() {
this.num = 0;
}
var a = new Counter(); // a.num 0
因为使用了关键字 new
构造,Count()
函数中的 this
绑定到一个新的对象,并且赋值给 a
。通过 console.log
打印 a.num
,会输出 0。
如果我们想每过一秒将 a.num
的值加 1,该如何实现呢?可以使用 setInterval()
函数。1
2
3
4
5
6
7
8
9
10
11
12
13function Counter() {
this.num = 0;
this.timer = setInterval(function add() {
this.num++;
console.log(this.num);
}, 1000);
}
var b = new Counter();
// NaN
// NaN
// NaN
// ...
首先函数 setInterval
没有被某个声明的对象调用,也没有使用 new
关键字,再之没有使用 bind
, call
和 apply
。setInterval
只是一个普通的函数。实际上 setInterval
里面的 this
绑定到全局对象 window
上了。
使用箭头函数!使用箭头函数就不会导致 this
被绑定到全局对象。1
2
3
4
5
6
7
8
9
10
11
12function Counter() {
this.num = 0;
this.timer = setInterval(() => {
this.num++;
console.log(this.num);
}, 1000);
}
var b = new Counter();
// 1
// 2
// 3
// ...
通过 Counter
构造函数绑定的 this
将会被保留。在 setInterval
函数中,this
依然指向我们新创建的 b
对象。
3.3. 不绑定 arguments
箭头函数还有一个比较有特点的地方就是其不绑定 arguments,即如果你在箭头函数中使用 arguments 参数不能得到想要的内容。1
2
3let arrowfunc = () => console.log(arguments.length)
arrowfunc()
// arguments is not defined
3.4. 适用场景及注意点
- 箭头函数适合于无复杂逻辑或者无副作用的纯函数场景下,例如:用在 map、reduce、filter 的回调函数定义中
- 箭头函数的亮点是简洁,但在有多层函数嵌套的情况下,箭头函数反而影响了函数的作用范围的识别度,这种情况不建议使用箭头函数
- 箭头函数要实现类似纯函数的效果,必须剔除外部状态。所以箭头函数不具备普通函数里常见的 this、arguments 等,当然也就不能用 call()、apply()、bind() 去改变 this 的指向
- 箭头函数不适合定义对象的方法(对象字面量方法、对象原型方法、构造器方法),因为箭头函数没有自己的 this,其内部的 this 指向的是外层作用域的 this
- 箭头函数不适合定义结合动态上下文的回调函数(事件绑定函数),因为箭头函数在声明的时候会绑定静态上下文
1 | const json = {bar: 1, fn: () => console.log(this.bar)}; |
1 | function Foo() { |
1 | const Message = (text) => { |
1 | const button = document.querySelector('button'); |
4. 字符串
4.1. includes 方法
1 | // 判断字符串中是否包含某个字符串 |
4.2. endsWith、startsWith 方法
1 | // 判断字符串是否以某一个字符串开始或结束 |
4.3. 字符串内容重复输出
1 | 'a'.repeat(5);//aaaaa 重复输出5遍 |
4.4. 字符串补全
1 | // 参数1:[number] 目标字符串长度 |
4.5. 原生支持模板语言
1 | // es5 |