Kyle's Notebook

ES6 语法总结

Word count: 5.8kReading time: 31 min
2019/06/02

ES6 语法总结

let,const 关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ES6 强制开启严格模式(ES5:use strict)
function test() {
for (let i = 1; i < 3; i++) {
console.log(i);
}
console.log(i); // 错误:let声明变量作用域为块作用域(不能在花括号外引用);

let a = 1; // 错误:使用let不能重复声明
let a = 2;
}

function last() {
const PI = 3.1415926; // const声明变量是块作用域,声明时必须赋值
const k = { // const声明变量为常量,const声明对象时内部指针可以改变
a: 1
};
k.b = 3;
console.log(PI, k);
}

test();
last();

结构赋值

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 数组结构赋值
{
let a, b, rest;
[a, b] = [1, 2];
console.log(a, b); // let a = 1, b = 2;
}
{
let a, b, rest;
[a, b, ...rest] = [1, 2, 3, 4, 5, 6];
console.log(a, b, rest); // let a = 1, b = 2, rest = [3, 4, 5, 6]
}

// 对象结构赋值
{
let a, b;
({a, b} = {a: 1, b: 2}); // let a = 1, b = 2;
console.log(a, b);
}
{
let a, b, c, rest;
[a, b, c = 3] = [1, 2]; // 如果c没有默认值,则会undefined
console.log(a, b, c);
}
{
let a = 1;
let b = 2;
[a, b] = [b, a]; // 变量交换
console.log(a, b);
}
{
function f() {
return [1, 2]
}

let a, b;
[a, b] = f(); // 多个返回值(解包)
console.log(a, b);
}
{
function f() {
return [1, 2, 3, 4, 5]
}

let a, b, c;
[a, , , b] = f(); // 只获取特定位置上的返回值
console.log(a, b);
}
{
function f() {
return [1, 2, 3, 4, 5]
}

let a, b, c;
[a, , ...b] = f(); // 跳过不需要的返回值,并把剩余的不定个值赋到数组上
console.log(a, b);
}
{
let o = {p: 42, q: true};
let {p, q} = o; // 传递后解包赋值
console.log(p, q);
}

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

{
let metaData = {
title: 'abc',
test: [{
title: 'test',
desc: 'description'
}]
};
let {title: esTitle, test: [{title: cnTitle}]} = metaData; // 左右格式一致,则可以获取对应位置上的值
console.log(esTitle, cnTitle); // let esTitle = 'abc', enTitle = 'test'
Object.assign(metaData, {'title': 'def'}) // 对metaData的title赋值为def
}

正则扩展

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
{
// ES5 的正则对象构造函数
let regex = new RegExp('xyz', 'i'); // 第一个参数是字符串,第二个是修饰符
let regex2 = new RegExp(/xyz/i); // 第一个参数是正则表达式,不接受第二个参数,否则会报错

console.log(regex.test('xyz123'), regex2.test('xyz123')); // true, true

let regex3 = new RegExp(/abc/ig, 'i');
console.log(regex3.flags); // 原有正则对象的修饰符是ig,它会被第二个参数i覆盖
}

// 字符串对象的4个使用正则表达式的方法: match(),replace(),search(),split()这四个方法全部调用RegExp的实例的方法。
// {
// let regex = new RegExp('xyz', 'ig');
// console.log(regex.test('xyz0XYZ1xyz2'), regex.exec('xyz0XYZ1xyz2'));
// }

// y修饰符
{
let s = 'bbbb_bbb_bb_b';

let a1 = /b+/g;
let a2 = /b+/y;

console.log(a1.exec(s), a2.exec(s)); // ["bbbb"],["bbbb"]
console.log(a1.exec(s), a2.exec(s)); // ["bbb"],null

console.log(a1.sticky, a2.sticky); //表示是否开启了粘连模式
}

// u修饰符(Unicode编码,正则表达式中待匹配的字符串含有大于0xFFFF的字符则必须加u)
{
console.log('u修饰符', /^\uD83D/.test('\uD83D\uDC2A')); // true
console.log('u修饰符', /^\uD83D/u.test('\uD83D\uDC2A')); // false(u把后面当成一个字符)

// 大括号表示Unicode字符,只有加上u才能识别
console.log(/\u{61}/.test('a')); // false
console.log(/\u{61}/u.test('a')); // true
console.log(/\u{20BB7}/u.test('𠮷')); // true

// 点(.)字符不能识别码点大于0xFFFF的Unicode字符,必须加上u修饰符。
let s = '𠮷';
console.log('大于0xFFFF的Unicode字符', /^.$/.test(s)); // false
console.log('使用u字符', /^.$/u.test(s)); // true

// 使用u修饰符后,所有量词都会正确识别大于码点大于0xFFFF的Unicode字符。
console.log('量词', /a{2}/.test('aa')); // true
console.log('量词', /a{2}/u.test('aa')); // true
console.log('量词', /𠮷{2}/.test('𠮷𠮷')); // false
console.log('量词', /𠮷{2}/u.test('𠮷𠮷')); // true
}

{
// 正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是行终止符(line terminator character)除外
// U+000A 换行符(\n)
// U+000D 回车符(\r)
// U+2028 行分隔符(line separator)
// U+2029 段分隔符(paragraph separator)
// 只是一个提案目前还不支持
// let reg=/test.go/s;
// console.log(reg.test('test\ngo'));
// console.log(reg.test('test\ngo'));
console.log('s变通方法', /foo.bar/.test('foo\nbar'));
console.log('s变通方法', /foo[^]bar/.test('foo\nbar'));
}

字符串扩展

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

// Unicode字符表示
{
console.log('a', `\u0061`); // 反引号把Unicode转换成字符串
console.log('s', `\u20BB7`); // 大于0xFFFF时不能按一个字符处理,需要使用花括号
console.log('s', `\u{20BB7}`);
}
{
let s = '𠮷';
console.log('length', s.length); // 2
console.log('0', s.charAt(0));
console.log('1', s.charAt(1));
console.log('at0', s.charCodeAt(0));
console.log('at1', s.charCodeAt(1));

let s1 = '𠮷a';
console.log('length', s1.length);
console.log('code0', s1.codePointAt(0)); // 134071(10进制)
console.log('code0', s1.codePointAt(0).toString(16)); // 20BB7(16禁止)
console.log('code1', s1.codePointAt(1)); // 57271
console.log('code2', s1.codePointAt(2));
}
{
console.log(String.fromCharCode("0x20bb7")); // xxx
console.log(String.fromCodePoint("0x20bb7")); // 吉
}
{
let str = '\u{20bb7}abc';
for (let i = 0; i < str.length; i++) {
console.log('es5', str[i]);
}
for (let code of str) { // 字符串遍历
console.log('es6', code);
}
}

// 字符串扩展
{
let str = "string";
console.log('includes', str.includes("c"));
console.log('start', str.startsWith('str'));
console.log('end', str.endsWith('ng'));
}
{
let str = "abc";
console.log(str.repeat(2)); // 字符串重复2此
}

// 字符串模板
{
let name = "list";
let info = "hello world";
let m = `i am ${name},${info}`; // 反引号定义嵌入模板字符串(scala为s,python为f)
console.log(m);
}

{
console.log('1'.padStart(2, '0')); // 字符串必须满足长度为2,不足则以0补全
console.log('1'.padEnd(2, '0'));
}

{
// 标签模板(防止csrf攻击)
let user = {
name: 'list',
info: 'hello world'
};
console.log(`i am ${user.name},${user.info}`); // i am list,hello world
console.log(abc`i am ${user.name},${user.info}`); // i am ,,,listhello world

function abc(s, v1, v2) {
console.log(s, v1, v2); // ["i am", ",", "", raw: Array[3]] "list" "hello world"
return s + v1 + v2
}
}

{
console.log(String.raw`Hi\n${1 + 2}`); // 对所有\转义
console.log(`Hi\n${1 + 2}`);
}

数值扩展

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
{
console.log('B', 0B111110111); // 二进制转十进制
console.log(0o767); // 八进制转十进制
}

{
console.log('15', Number.isFinite(15)); // true,有效数值(非无穷)
console.log('NaN', Number.isFinite(NaN)); // false
console.log('1/0', Number.isFinite('true' / 0)); // false
console.log('NaN', Number.isNaN(NaN)); // true
console.log('0', Number.isNaN(0)); // false

}

{
console.log('25', Number.isInteger(25)); // true
console.log('25.0', Number.isInteger(25.0)); // true
console.log('25.1', Number.isInteger(25.1)); // false
console.log('25.1', Number.isInteger('25')); // false
}

{
console.log(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
console.log('10', Number.isSafeInteger(10)); // // 是否在正负2^50之间
console.log('a', Number.isSafeInteger('a'));
}

{
console.log(4.1, Math.trunc(4.1)); // 取整数部分
console.log(4.9, Math.trunc(4.9));
}

{
console.log('-5', Math.sign(-5)); // -1
console.log('0', Math.sign(0)); // 0
console.log('5', Math.sign(5));
console.log('50', Math.sign('50')); // 1
console.log('foo', Math.sign('foo')); // NaN
}

{
console.log('-1', Math.cbrt(-1)); // 立方根
console.log('8', Math.cbrt(8));
}

数组扩展

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
46
47
48
49
50
51
52
53
54
55
{
let arr = Array.of(3, 4, 7, 9, 11);
console.log('arr=', arr);

let empty = Array.of();
console.log('empty', empty);
}

{
let p = document.querySelectorAll('p'); // 获取所有p标签
let pArr = Array.from(p); // 把p标签集合转化为数组
pArr.forEach(function (item) {
console.log(item.textContent);
});

console.log(Array.from([1, 3, 5], function (item) { // 相当于map()函数
return item * 2
}));
}

{
console.log('fill-7', [1, 'a', undefined].fill(7)); // 把数组元素替换为7
console.log('fill,pos', ['a', 'b', 'c'].fill(7, 1, 3)); // 从下标为1开始、一直到第3个都替换为7
}

{
// 需要import Lottery from './lottery';
for (let index of ['1', 'c', 'ks'].keys()) { // 获取数组下标
console.log('keys', index);
}
for (let value of ['1', 'c', 'ks'].values()) { // 获取数组值
console.log('values', value);
}
for (let [index, value] of ['1', 'c', 'ks'].entries()) { // 相当与python的enumerate
console.log('values', index, value);
}
}

{
console.log([1, 2, 3, 4, 5].copyWithin(0, 3, 4));
}

{
console.log([1, 2, 3, 4, 5, 6].find(function (item) { // 查找第一个满足条件的元素
return item > 3
}));
console.log([1, 2, 3, 4, 5, 6].findIndex(function (item) {
return item > 3
}));
}

{
console.log('number', [1, 2, NaN].includes(1)); // 判断是否包含元素
console.log('number', [1, 2, NaN].includes(NaN));
}

函数扩展

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 默认参数
{
function test(x, y = 'world') {
console.log('默认值', x, y);
}

test('hello');
test('hello', 'kill');
}
{
let x = 'test';

function test2(x, y = x) {
console.log('作用域', x, y);
}

function test3(c, y = x) {
console.log('作用域', c, y);
}

test2('kill'); // kill, kill
test(); // undefined, undefined

test3('kill') // kill, test
}

// 动态参数
{
function test3(...arg) {
for (let v of arg) {
console.log('rest', v);
}
}

test3(1, 2, 3, 4, 'a');
}

// 扩展运算符
{
console.log(...[1, 2, 4]); // 1, 2, 4,把数组拆成三个离散值
console.log('a', ...[1, 2, 4]);
}


// 箭头函数(匿名函数)
{
let arrow = v => v * 2;
let arrow2 = () => 5; // 无参数时用()
console.log('arrow', arrow(3));
console.log(arrow2());

}

// 尾调用(提升性能)
{
function tail(x) {
console.log('tail', x);
}

function fx(x) { // 返回tail函数的调用结果
return tail(x)
}

fx(123)
}

对象扩展

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{

let o = 1;
let k = 2;

// ES5对象
let es5 = {
o: o,
k: k
};

// ES6对象
let es6 = {
o,
k
};

console.log(es5, es6);


// ES5方法
let es5_method = {
hello: function () {
console.log('hello');
}
};

// ES6方法
let es6_method = {
hello() {
console.log('hello');
}
};
console.log(es5_method.hello(), es6_method.hello());
}

{
// ES5
let a = 'b';
let es5_obj = {
a: 'c',
b: 'c'
};

// ES6(key可以为变量)
let es6_obj = {
[a]: 'c'
};

console.log(es5_obj, es6_obj);
}

{

console.log('字符串', Object.is('abc', 'abc'), 'abc' === 'abc'); // true, true
console.log('数组', Object.is([], []), [] === []); // true, true

console.log('拷贝', Object.assign({a: 'a'}, {b: 'b'})); // 两个对象合并成一个(不拷贝继承、不可枚举的属性)

let test = {k: 123, o: 456};
for (let [key, value] of Object.entries(test)) { // 相当python的items()
console.log([key, value]);
}
}

// {
// // 扩展运算符
// let {a, b, ...c} = {a: 'test', b: 'kill', c: 'ddd', d: 'ccc'};
// c = {
// c: 'ddd',
// d: 'ccc'
// }
// }

唯一类型:Symbol

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
// Symbol:独一无二的值
{
// 声明
let a1 = Symbol();
let a2 = Symbol();
console.log(a1 === a2); // false

let a3 = Symbol.for('a3'); // 类似于“常量池”
let a4 = Symbol.for('a3');
console.log(a3 === a4); // true
}

{
let a1 = Symbol.for('abc');
let obj = {
[a1]: '123', // 如a1的值不是Symbol则会报错
'abc': 345,
'c': 456
};
console.log('obj', obj); // 则对象中的key有Symbol('123')、'123'和'c'

for (let [key, value] of Object.entries(obj)) { // 获取对象中非Symbol属性
console.log('let of', key, value);
}

Object.getOwnPropertySymbols(obj).forEach(function (item) { // 获取对象中的Symbol属性
console.log(obj[item]);
});

Reflect.ownKeys(obj).forEach(function (item) { // 获取对象中所有属性
console.log('ownkeys', item, obj[item]);
})
}

数据结构 Set、Map

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Set
{
let list = new Set();
list.add(5);
list.add(7);
console.log('size', list.size); // 2
}
{
let arr = [1, 2, 3, 4, 5];
let list = new Set(arr);
console.log('size', list.size);
}
{
let list = new Set();
list.add(1);
list.add(2);
list.add(1);
console.log('list', list); // [1, 2]

let arr = [1, 2, 3, 1, '2'];
let list2 = new Set(arr);
console.log('unique', list2); // [1, 2, 3, '2']
}
{
let arr = ['add', 'delete', 'clear', 'has'];
let list = new Set(arr);

console.log('has', list.has('add')); // 存在于集合
console.log('delete', list.delete('add'), list); // 从集合中删除
list.clear();
console.log('list', list);
}
{
let arr = ['add', 'delete', 'clear', 'has'];
let list = new Set(arr);

for (let key of list.keys()) { // key和value是一样的
console.log('keys', key);
}
for (let value of list.values()) {
console.log('value', value);
}
for (let [key, value] of list.entries()) {
console.log('entries', key, value);
}
list.forEach(function (item) {
console.log(item);
})
}

// WeakSet,元素只能是对象(弱引用,不检测GC),不能遍历
{
let weakList = new WeakSet();
let arg = {};

weakList.add(arg);
// weakList.add(2); // 不能存放对象以外的值

console.log('weakList', weakList);
}

// Map
{
let map = new Map();
let arr = ['123'];
map.set(arr, 456); // 注意添加元素方法与Set不同
console.log('map', map, map.get(arr));
}
{
let map = new Map([['a', 123], ['b', 456]]);
console.log('map args', map); // Map {"a" => 123, "b" => 456}
console.log('size', map.size); // 2
console.log('delete', map.delete('a'), map); // Map {"b" => 456}
console.log('clear', map.clear(), map); // Map {}
// 遍历方法与Set一样
}

// WeakMap
{
let weakmap = new WeakMap();

let o = {};
weakmap.set(o, 123);
console.log(weakmap.get(o));
}

// Map、Array对比(增查改删)
{
let map = new Map();
let array = [];

map.set('t', 1); // 加入一个key-value
array.push({t: 1}); // 加入一个存在t属性为1的元素

let map_exist = map.has('t'); // true
let array_exist = array.find(i => i.t); // Object {t: 1}

map.set('t', 2); // 把key为t的value修改为2
array.forEach(i => i.t? i.t = 2: ''); // 先在数组中找到存在t属性的元素,再把它改为2,否则不操作

map.delete('t');
let index = array.findIndex(i => i.t); // 删除存在t属性的元素
array.splice(index, 1)
}

// Set、Array对比(增查改删)
{
let set = new Set();
let array = [];

set.add({t: 1});
array.push({t: 1});

let set_exist = set.has({t: 1}); // 查不到(不能根据对象来查,应该在加入前先保存其引用,通过引用来查)
let array_exist = array.find(i => i.t); // Object {t: 1}

set.forEach(i => i.t? i.t = 2: '');
array.forEach(i => i.t? i.t = 2: ''); // 先在数组中找到存在t属性的元素,再把它改为2,否则不操作

set.forEach(i => i.t? set.delete(i): ''); // 遍历,根据值删除
let index = array.findIndex(i => i.t); // 删除存在t属性的元素(根据索引)
array.splice(index, 1)

}

// Map、Set、Object对比(增查改删)
{
let item = {t: 1};
let map = new Map();
let set = new Set();
let obj = {};

map.set('t', 1);
set.add(item);
obj['t'] = 1;

let map_exist = map.has('t');
let set_exist = set.has(item);
let obj_exist = 't' in obj;

map.set('t', 2);
item.t = 2; // 对于Set,直接修改所存放的引用,不需要在Set中修改
obj['t'] = 2;

map.delete('t');
set.delete(item);
delete obj['t'];
}

// 优先使用Map,需确保唯一时使用Set

代理:Proxy 和 Reflect

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Proxy
{

// 原始对象(存放数据)
let obj = {
time: '2017-03-11',
name: 'net',
_r: 123
};

// 代理对象(存放访问方式)
let monitor = new Proxy(
obj,
{
// monitor.time,代理对象属性的读取,把从obj取出的time属性值中的2017修改为2018并返回
get(target, key) {
return target[key].replace('2017', '2018')
},

// monitor.name = 'test',代理对象设置属性,只允许修改name属性
set(target, key, value) {
if (key === 'name') {
return target[key] = value;
}
else {
return target[key];
}
},

// 'name' in monitor,代理key in object操作,只允许访问name属性
has(target, key) {
if (key === 'name') {
return target[key]
}
else {
return false;
}
},

// delete monitor.name,代理delete
deleteProperty(target, key) {
if (key.indexOf('_') > -1) {
delete target[key];
return true;
}
else {
return target[key]
}
},

// monitor.keys,代理Object.keys, Object.getOwnPropertySymbols, Object.getOwnPropertyNames
ownKeys(target) {
return Object.keys(target).filter(item => item != 'time')
}
}
);

console.log('get', monitor.time);

monitor.time = '2018';
monitor.name = 'mukewang';
console.log('set', monitor.time, monitor);

console.log('has', 'name' in monitor, 'time' in monitor);

delete monitor.time;
console.log('delete',monitor);

delete monitor._r;
console.log('delete',monitor);
console.log('ownKeys', Object.keys(monitor));
}

// Reflect
{
let obj = {
time: '2017-03-11',
name: 'net',
_r: 123
};
console.log('Reflect get', Reflect.get(obj, 'time'));

Reflect.set(obj, 'name', 'mukewang');
console.log(obj);
console.log('has', Reflect.has(obj, 'name'));
}


// 实践
{
function validator(target, validator) {
return new Proxy(
target,
{
_validator: validator,
set(target, key, value, proxy) {
if (target.hasOwnProperty(key)) {
let va = this._validator[key];
if (!! va(value))
return Reflect.set(target, key, value, proxy);
else
throw Error(`不能设置${key}`);
}
else
throw Error(`${key} 不存在`);
}
}
)
}

const personValidators = {
name(val) {
return typeof val === 'string';
},
age(val) {
return typeof val === 'number' && val > 18;
}
};

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
return validator(this, personValidators);
}
}

const person = new Person('lilei', 30);
console.info(person);
}

类与对象

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{
// 基本定义和生成实例
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
}

let v_parent = new Parent('v');
console.log('构造函数和实例', v_parent);
}

{
// 继承
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
}

class Child extends Parent {
}

console.log('继承', new Child());
}

{
// 继承传递参数
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
}

class Child extends Parent {
constructor(name = 'child') {
super(name);
this.type = 'child';
}
}

console.log('继承传递参数', new Child('hello'));
}

{
// getter,setter
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}

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

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

let v = new Parent();
console.log('getter', v.longName);
v.longName = 'hello';
console.log('setter', v.longName);
}

{
// 静态方法
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}

static tell() {
console.log('tell');
}
}

Parent.tell();

}

{
// 静态属性
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}

static tell() {
console.log('tell');
}
}

Parent.type = 'test';

console.log('静态属性', Parent.type);
}

异步: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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
{
// 基本定义
let ajax = function (callback) {
console.log('执行'); // 回调:先输出执行,1s后才执行下面的函数
setTimeout(function () {
callback && callback.call()
}, 1000);
};
ajax(function () {
console.log('timeout1');
})
}

{
let ajax = function () {
console.log('执行2');
return new Promise(
function (resolve, reject) {
setTimeout(function () {
resolve()
}, 1000);
}
)
};

ajax().then(function () {
console.log('promise', 'timeout2');
// 使用ajax()返回的对象,执行下一步操作,then的第一个参数即Promise中的resolve
}, '')
}

{
let ajax = function () {
console.log('执行3');
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve()
}, 1000);
})
};

ajax() // 执行ajax、再不断指定并执行下一步
.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve()
}, 2000);
});
})
.then(function () {
console.log('timeout3');
})
}

{
let ajax = function (num) {
console.log('执行4');
return new Promise(function (resolve, reject) {
if (num > 5) {
resolve()
}
else {
throw new Error('出错了')
}
})
};

ajax(6)
.then(function () {
console.log('log', 6);
}) // 执行ajax中的下一步操作
.catch(function (err) {
console.log('catch', err);
}); // 处理ajax中出现的异常

ajax(3)
.then(function () {
console.log('log', 3);
})
.catch(function (err) {
console.log('catch', err);
});
}


// 模拟加载图片:所有图片加载完成才显示
{
// 图片记载完再添加到页面
function loadImg(src) {
return new Promise(
(resolve, reject) => {
let img = document.createElement('img');
img.src = src;
img.onload = function () {
resolve(img);
};
img.onerror = function (err) {
reject(err);
}
}
)
}

function showImgs(imgs) {
imgs.forEach(
function (img) {
document.body.appendChild(img);
}
);
}

Promise.all([ // 数组所有promise实例视为一个,当所有promise实例发生变化时才会执行then
loadImg('http://xxxx'),
loadImg('http://xxx')
//
]).then(showImgs)

}

// 模拟加载图片:先加载完先显示
{
function loadImg(src) {
return new Promise(
(resolve, reject) => {
let img = document.createElement('img');
img.src = src;
img.onload = function () {
resolve(img);
};
img.onerror = function (err) {
reject(err)
}
}
)
}

function showImgs(img) {
let p = document.createElement('p');
p.appendChild(img);
document.body.appendChild(p);
}

Promise.race([
loadImg('http://xxxx'),
loadImg('http://xxx')
]).then(showImgs)
}

迭代器(Iterator)

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
// 使用for...of必须实现iterator接口

{
let arr = ['hello', 'world'];
let map = arr[Symbol.iterator](); // 创建迭代器
console.log(map.next());
console.log(map.next());
console.log(map.next());
}

// 可迭代对象
{
let obj = {
start: [1, 3, 2],
end: [7, 9, 8],
[Symbol.iterator]() {
let self = this;
let index = 0;
let arr = self.start.concat(self.end);
let len = arr.length;
return {
next() {
if (index < len)
return {value: arr[index++], done: false};
else
return {value: arr[index++], done: true};
}
}
}
};
for (let key of obj)
console.log(key);
}

{
let arr = ['hello', 'world'];
for (let value of arr)
console.log('value', value);
}

生成器(Generator)

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
{
// genertaor基本定义
let tell = function* () {
yield 'a';
yield 'b';
return 'c'
};

// 每次调用next时会调用yield之前的语句,然后停止等待下一次调用以此类推
let k = tell();
console.log(k.next());
console.log(k.next());
console.log(k.next());
console.log(k.next());
}

// 使用generator实现迭代
{
let obj = {};
obj[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};

for (let value of obj)
console.log('value', value);

}

// 使用generator实现状态机
{
let state = function* () {
while (1) {
yield 'A';
yield 'B';
yield 'C';
}
};
let status = state();
console.log(status.next());
console.log(status.next());
console.log(status.next());
console.log(status.next());
console.log(status.next());
}

// {
// let state = async function () {
// while (1) {
// await 'A';
// await 'B';
// await 'C';
// }
// };
// let status = state();
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// }

// 模拟抽奖次数限制(避免维护剩余次数的全局变量)
{
let draw = function (count) {
// 分离抽奖逻辑
console.log(`剩余${count}次`);
};

let residue = function* (count) {
while (count > 0) {
count--;
yield draw(count);
}
};

let star = residue(5); // 初始抽奖次数
let btn = document.createElement('buttot');
btn.id = 'start';
btn.textContent = '抽奖';
document.body.appendChild(btn);
document
.getElementById('start')
.addEventListener('click', function () {
star.next();
}, false)
}

// 长轮询(Websocket浏览器兼容性不好)
{
let ajax = function* () {
yield new Promise(
function (resolve, reject) {
setTimeout(
function () {
resolve({code: 0}) // 成功后返回{code: 0}
}, 200 // 等待200毫秒
)
}
)
};

let pull = function () {
let generator = ajax();
let step = generator.next();
step.value.then(
function (d) {
if (d.code != 0) // 返回状态不为0,则继续轮询,间隔1秒
setTimeout(
function () {
console.log('wait');
pull()
}, 1000
);
else
console.info(d);
}
)
}
}

装饰器(Decorator)

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 使用装饰器函数扩展类的功能
{
let readonly = function (target, name, descriptor) {
descriptor.writable = false;
return descriptor
};

class Test {
@readonly
time() {
return '2017-03-11'
}
}

let test = new Test();

// test.time=function(){
// console.log('reset time');
// };

console.log(test.time());
}


{
let typename = function (target, name, descriptor) {
target.myname = 'hello';
};

@typename
class Test {

}

console.log('类修饰符', Test.myname);
// 第三方库修饰器的js库:core-decorators; npm install core-decorators
}

// 模拟埋点系统
{
let log = (type) => {
return function (target, name, descriptor) {
let src_method = descriptor.value;
descriptor.value = (...arg) => {
src_method.apply(target, arg);
console.info(`log ${type}`); // 模拟埋点
}
}
};

class AD {
@log('show')
show() {
console.info('show');
}

@log('click')
click() {
console.info('click');
}
}

let ad = new AD();
ad.show();
ad.click();
}
CATALOG
  1. 1. ES6 语法总结
    1. 1.1. let,const 关键字
    2. 1.2. 结构赋值
    3. 1.3. 正则扩展
    4. 1.4. 字符串扩展
    5. 1.5. 数值扩展
    6. 1.6. 数组扩展
    7. 1.7. 函数扩展
    8. 1.8. 对象扩展
    9. 1.9. 唯一类型:Symbol
    10. 1.10. 数据结构 Set、Map
    11. 1.11. 代理:Proxy 和 Reflect
    12. 1.12. 类与对象
    13. 1.13. 异步:Promise
    14. 1.14. 迭代器(Iterator)
    15. 1.15. 生成器(Generator)
    16. 1.16. 装饰器(Decorator)