从零开始的 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