前言
笔记仅记录了相比于第一次学习,重新理解的知识点
完整内容详见:《ECMAScript 6 入门》 阮一峰
总结
经历两个星期结合ES6的React实践,决定再回头看一遍阮一峰的ES6教程,发现收获多多,常看常新。
第一遍看时,比较敷衍,没有实践自然也理解不深,综合来说,阮一峰的教程更适合查漏补缺,而不是作为入门教材。
索引
- 解构赋值的用途
- 尾调用优化
- 扩展运算符的用途
- 数组的方法扩展
- 对象
- Set类型 : distinct Array
- Map类型:可扩展键名,值—值对
- Proxy对象
- Promise对象
- Iterator 迭代器
- Generator生成器
- async函数
- Class 类
1. 解构赋值的用途
① 交换变量值: [x, y] = [y, x]
② 函数返回值的获取更便利: let [a, b, c ] = func()
③ 函数无序传参
有序传参:function func([x,y,z]) { }
func([1,2,3])
无序传参:function func({x, y, z}) { }
func({z: 3, y: 2 , x: 1})
④ 提取JSON数据更方便
⑤ 函数传参可设置默认值,如预设Ajax请求的参数
当传入Ajax请求的参数不声明async与cache值,默认都为true
jQuery.ajax = function (url, { async = true, cache = true}) {};
⑥ Map类型取键名/值 : for ( let [key, value] of map) { }
⑦ 加载CommonJS模块中的指定方法: import { func1 , func2 } from '../common.js'
2. 尾调用优化
在函数的最后一步(即return)中调用另一个函数,形如return g(a,b);
,叫做尾调用。
存储于内存中的函数调用记录(包含了调用内存位置、变量等信息),叫做调用帧,嵌套函数的调用帧形成了调用栈;这很浪费内存。
因此在return句中采用尾调用,当内层函数的调用不再用到外层函数中的信息,就可用最新内层函数的调用帧取代外层函数的调用帧,节省内存。
3. 扩展运算符的用途
① 取代concat()
合并数组: let arr = [...arr1, ...arr2];
② 与解构赋值并用,截取部分数组: let [item, ...rest] = array;
③ 分解对象类型的函数返回值: var { data, code, msg } = getData();
④ 字符串转数组: [...'hello] 等同于 'hello'.split('');
⑤ 正确识别32位的Unicode字符串: [ ...str ].length 获取unicode字符串正确长度
4. 数组的方法扩展
① array.find(function)
:查找第一个符合条件的数组元素
② array.findIndex()
:与indexOf功能相同,但findIndex优于可查找NaN元素
③ new Array(5).fill(0)
:创建数组并且初始化为全0
④ 数组元素遍历
array.keys()
:遍历键名
array.values()
:遍历键值
array.entries()
:遍历键值对
⑤ array.includes(value)
: 数组查找,可查找NaN
5. 对象
① let a = { [key]: value}
:用表达式作键名
② Object.is(value1, value2 )
: 严格一致,不会自动转换类型,准确性高于“===”
③ Object.assign(target, obj1, obj2 )
: 合并对象属性到第一个参数中;是浅拷贝(符合类型为引用)
④ object.__proto__属性
指向Object.prototype属性
object.__proto__属性
推荐使用的三个操作方法:
Object.setPrototypeOf(object, prototype)
Object.getPrototypeOf(obj);
Object.create()
⑤ prototype
与__proto__
属性
Array.prototype
:Array原型的所有方法
new Array(3).__proto__
: 原型实例的自有属性方法,内包含了Array.prototype中的所有方法
⑥ 对象的扩展:let { x, y, ...z } = { x: 1, y: 2, a: 3 , b: 4} ; 则 z = { a: 3 , b: 4 }
6. Set类型 : distinct Array
① .add()
② .size
③ .delete()
④ .has(value)
⑤ .clear()
⑥ Set转数组: Array.from(set)
数组去重: Array.from (new Set(array))
7. Map类型:可扩展键名,值—值对
① .size
② .set(key, value)
③ .get(key)
④ .has(key)
⑤ .delete(key)
⑥ .clear()
⑦ 遍历的顺序即插入的顺序
⑧ Map转数组: ...map
8. Proxy对象
进程与对象实体之间的拦截层
9. Reflect对象
用于部署对象的新方法;可以通过Reflect对象拿到语言内部的方法,如Object.defineProperty
10. Promise对象
① 封装了一个函数
② 对内部函数返回的resolve
与reject
进行分发处理(.then
与.catch
)
③ Promise新建后,立即执行
11. Iterator 迭代器
① Iterator.next()
的返回值: {value: 'value', done: false}
或 { value: undefined, done: true}
② 悄悄调用了可遍历数据的Iterator的情况:
解构赋值有序对象(数组、set)、
扩展运算符...
、
yield* 表达式: yield* [2,3,4] 等同于 yield 2; yield 3; yield 4;
③ let ... in
:遍历键名
④ let ... of
:遍历键值(适用于有Iterator接口的数据)
12. Generator生成器
① 相当于一个封装了多个状态的状态机
② 作用:生成并且返回一个遍历器对象
③ 调用后并不立即执行,而是返回一个指向内部状态的指针对象(遍历器对象)
④ 调用iterator.next()
,才是真正执行内部函数的时机
⑤ yield
可以嵌入普通语句中,但要放在圆括号中: console.log( 'hello' + (yield 123) );
⑥ yield表达式本身的返回值是undefined
,但可以用next(value)对上一个yield表达式赋值
⑦ yield * generator()
:在一个生成器函数中调用另一个生成器函数
⑧ 封装异步函数,实现回调
function* demo () {
// do something Part1
yield go(); // 相当于分离了异步的两个阶段,part1与part2
// do something Part2
}
let g = demo();
g.next(); // 执行part1
g.next(); // part1执行完之后,再执行part2
⑨ 重点理解:
Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
在第一次调用.next()
时,执行到yield
语句(yield语句本身也被执行)。等下一次next调用,执行下一段包含yield
语句的代码段。
function* demo () {
do thing 1
yield y1;
<---第一次执行next,执行到此处---->
do thing 2
yield y2;
<---第二次执行next,执行到此处---->
do thing 3
yield y3;
<---第三次执行next,执行到此处---->
do thing 4
yield y4;
<---第四次执行next,执行到此处---->
}
// 代码实例
var a = 0;
function* demo() {
console.log('in demo a = 3')
console.log(yield a=3);
console.log('in demo a = 4')
console.log(yield a=4);
console.log('in demo a = 5')
console.log(yield a=5);
}
let g = demo();
console.log('首次next');
console.log(a);
console.log( g.next());
console.log(a);
console.log('二次next')
console.log(a);
console.log( g.next())
console.log(a);
console.log('三次next')
console.log(a);
console.log( g.next())
console.log(a);
13. async函数
是generator的语法糖,简化了异步操作。相比generator,async具有以下优点:
① 内置执行器,单行调用即可完成generator函数的所有.next()
② 更具有语义性
③ 适用性更广
yield命令:只能后跟 Thunk 或Promise
await命令:可后跟Promise对象与原始值
④ async函数的返回值是Promise对象
async将generator返回的Iterator对象自动执行后,并将结果封装为一个Promise对象,便于后期处理。
return await 123;
==> 转为resolve状态的Promise对象
async中return语句返回值,传入.then()
作回调参数。
return Promise.reject('出错了');
==> 转为reject状态的Promise对象
async中抛出错误,返回reject状态的Promise对象,传入.catch()
方法
⑤ forEach中的async是并发操作的,应该改用for循环
// 不推荐用forEach写法
function dbFuc(db) { //这里不需要 async
let docs = [{}, {}, {}];
// 可能得到错误结果
docs.forEach(async function (doc) {
await db.post(doc);
});
}
// 推荐用for循环
async function dbFuc(db) {
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}
14. Class 类
① super
super()
: 代表父类的构造函数传入父类的this,等同于Class.prototype.constructor.call(this)
super
:指向父类的原型对象,等同于Class.prototype
,可用于调用父类的静态方法
② prototype
与__proto__
子类的__proto__
指向父类
,表示构造函数的继承
子类的prototype.__proto__
指向父类的prototype
属性, 表示方法的继承
子类实例的__proto__.__proto__
指向父类实例的__proto__属性