从零开始的 ECMAScript 6 不完全攻略,轻扫盲向

0. 块级作用域

let变量在不同块级作用域中不影响:

1
2
3
4
for (let i = 1; i < 3; i++) {
console.log(i);
}
console.log(i); // 此行将报错: ReferenceError 未定义

重复声明变量会导致无法编译:

1
2
let a = 1;
let a = 2; // 此行将报错

一次声明后无法再次赋值的const类型:

1
2
const PI = 3.1415926; // 必须在声明时就立刻赋值
PI = 2; // 此行将报错,const类型值不可改变

const声明并非不可修改,而是不可重新赋值

1
2
3
4
5
const k = [] // 引用类型依然可以修改
k.b = 1;
k.a = 2;
console.log(k); // 输出[b: 1, a: 2]
k=[]; // 此行将报错,const声明的变量不可重新赋值

1. 数组扩展

将一串字符转换为数组

1
2
let arr = Array.of(3,4,7,9,11);
console.log(arr); // [3, 4, 7, 9, 11]

将其他对象转换为数组

1
2
3
let set1 = new Set();
set1.add(1).add(2).add(3)
console.log(Array.from(set1)) // [1,2,3] map array一样同理

数组加工

1
2
3
4
5
let t = Array.from([1,3,5], (i) => i*2)
console.log(t);// 输出 [2,6,10]

let t = Array.from([1,2,3], function(i){return i+1})
console.log(t);// 输出 [2,3,4]

数组遍历 entries()、keys()、values()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"

2. 对象扩展

ES5 与 ES6 中写法对比

1
2
3
4
5
6
7
8
9
10
11
12
let a = 1;
let b = 2;

let es5 = {
a:a,
b:b
};

let es6 = {
a,
b
};

数组方法表示更简明

1
2
3
4
5
6
7
8
9
10
11
let es5_method = {
hello: function() {
console.log('hello');
}
};

let es6_method = {
hello() {
console.log('hello');
}
};

属性表达式 可以在对象中使用变量定义,这在ES5以前不行

1
2
3
let a = 'b';
let obj = { [a]: 1 };
console.log(obj); // { b: 1}

新增API

1
2
3
console.log('字符串',Object.is('abc','abc'),'abc'==='abc');
console.log('数组',Object.is([],[]),[]===[]);
console.log('拷贝',Object.assign({a:'a'},{b:'b'}));

3. 函数扩展

参数默认值

1
2
3
4
5
function test(x, y = 'world'){
console.log('默认值',x,y);
}
test('hello'); // 'hello world'
test('hello','you'); // 'hello you'

可以使用数组形式接收若干参数

1
2
3
4
5
function test(...arg){
for(let one of arg){
console.log(one);
}
}

箭头函数

1
2
let arrow = a => a*2; // 带参数
let arrow2 = () => 5; // 无参

尾调用 可解决递归带来的资源消耗

1
2
3
4
5
6
7
function tail(x){
console.log('tail',x);
}
function fx(x){
return tail(x)
}
fx(123)

4. 数组解构赋值

变量交换将不再需要中间变量

1
2
3
4
let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b); // a=2 b=1

更直观的变量赋值

1
2
3
let a,b;
[a,b] = [1,2];
console.log(a,b); // a=1, b=2

可以选择性接收参数

1
2
3
let a,b;
[a,,,b] = [1,2,3,4,5];
console.log(a,b); // a=1, b=4

也可以是数组

1
2
3
let a,b;
[a,,...b] = [1,2,3,4,5]; // 注意这里 ... 的作用
console.log(a,b); // a=1, b=[3,4,5]

5. 对象解构赋值

按key value匹配

1
2
3
4
5
6
let o = {q:42,p:true,c:99};
let {p=false,q,k=0,c} = o;
console.log(p,q,k,c);

let {a=10,b=5}={a:3};
console.log(a,b);

使用场景模拟

1
2
3
4
5
6
7
8
9
10
11
let metaData={
title:'abc',
test:[{
title:'test',
desc:'description'
}]
}
let {title:esTitle,test:[{title:cnTitle}]}=metaData;
console.log(esTitle,cnTitle); // abc test
// let {title,test} = metaData;
// console.log(title,test[0].title);

6. 新数据类型 symbol

具有唯一性

1
2
3
4
5
6
let a1 = Symbol();
let a2 = Symbol();
console.log(a1===a2); // false
let a3 = Symbol.for('a3');//寻找a3,找不到,创建
let a4 = Symbol.for('a3');//寻找a3,找到,赋值
console.log(a3===a4); // true

使用场景模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let a1 = Symbol.for('abc');
let obj = {
[a1]:'123',
'abc':345,
'c':456
};
console.log(obj);//{abc: 345, c: 456, Symbol(abc): "123"}

for(let [key,value] of Object.entries(obj)){
console.log('let of',key,value);
// let of abc 345
// let of c 456
}

Object.getOwnPropertySymbols(obj).forEach(function(item){
console.log(obj[item]); // 123
})

Reflect.ownKeys(obj).forEach(function(item){
console.log('ownkeys',item,obj[item]);
// ownkeys abc 345
// ownkeys c 456
// ownkeys Symbol(abc) 123
})

7. 数据结构set与map

set的元素唯一特性(可做数组去重)

1
2
3
let arr = [1,1,1,4,5];
let list = new Set(arr);
console.log(list.size); // 3

set中比较是使用严等于,数据类型不转换

1
2
3
let arr = [1,2,3,1,'2'];
let list2 = new Set(arr);
console.log(list2); // {1, 2, 3, "2"}

通过增删改查来比较 Map Set Array Object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
let map = new Map();
let set = new Set();
let arr = [];
let obj = {};
let temp = {a:1};

// 增
map.set('a',1);

set.add(temp);

arr.push({a:1});

obj.a=1; // obj['a']=1;

// 删

map.delete('a');

set.forEach(item => item.a ? delete(item.a) : null);// set.delet(temp)

let index = arr.findIndex(item => item.a);
arr.splice(index, 1);

delete obj.a;// delete obj['a']

// 改

map.set('a',2);

set.forEach(item => item.a ? item.a=2 : null);// temp.a = 2;

arr.forEach(item => item.a ? item.a=2 : null);

obj.a = 2;// obj['a']=2;

// 查
let map_exist = map.has('a');

let set_exist = set.has({a:1});//false
let set_exist1 = set.has(temp);//true

let arr_exist = arr.find(item => item.a);

let obj_exist = 'a' in obj;

8. 对象代理一

1
2
3
4
5
6
7
8
9
10
let obj={
time:'2018-06-18',
name:'old'
};

console.log(Reflect.get(obj,'time'));// 2018-06-18
Reflect.set(obj,'name','new');
Reflect.deleteProperty(obj, 'time');
console.log(obj);// {name: "new"}
console.log(Reflect.has(obj,'name'));// true

9. 类的实现

父类生成

1
2
3
4
5
6
7
8
class Parent{
// 构造函数
constructor(name='fa'){
this.name = name;
}
}
// 实例化
let a = new Parent();

子类继承

1
2
3
4
5
class Child extends Parent{

}

let b = new Child();

继承传递参数

1
2
3
4
5
6
7
8
9
class Child extends Parent{
constructor(name2='child'){
super(name2); // 相当于向父类构造函数传参,需写在最前
this.type = 'child';
}
}

let c = new Child('new');
console.log(c); // {name: "new", type: "child"}

Getter Setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Parent{
constructor(name='js'){
this.name = name;
}

get longName(){
return 'get:'+this.name
}

set longName(value){
this.name=value;
}
}

let v = new Parent();
console.log('getter',v.longName); // getter get:js

v.longName='javascript';
console.log('setter',v.longName); // setter get:javascript

静态方法

1
2
3
4
5
6
7
class Parent{
static say(){
console.log('hello world');
}
}

Parent.tell(); // hello world

静态属性

1
2
3
4
5
6
7
class Parent{    

}

Parent.type='test';

console.log(Parent.type); // test

10. Promise

一个模拟的回调函数案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
let callback = (code) => {
console.log('开始运行');
return new Promise( (resolve,reject) => {
setTimeout(function () {
if (code === 0) {
resolve('正常运行');
} else {
reject('参数错误');
}
}, 1000);
})
};

let test = 0;

callback(test)
.then(( msg ) => {
console.log( msg );
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve('继续执行');
}, 1500);
});
})
.then(( msg ) => {
console.log( msg );
console.log('全部执行完毕');
})
.catch((e) => {
console.log(e);
})

// 假设 test = 0 时控制台输出:
// 开始运行
// 正常运行 (1s后)
// 继续执行 (1.5s后)
// 全部执行完毕 (1.5s后)

// 假设 test = 1 时控制台输出:
// 开始运行
// 参数错误 (1s后)

11. 模块化

a.js中导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let CL = 'R';
let fn = () => {
console.log('a function');
}
class Test{
test(){
console.log('a class');
}
}

export default {
CL,
Test,
fn
}

b.js中引入

1
2
3
4
5
6
7
8
import all from './b.js';

console.log(all.CL); // R

all.fn(); // a function

let t1 = new all.Test();
t1.test(); // a class