1.新特性实例
-
includes
Array.prototype.includes用来判断数组是否包含某个元素的,Array.prototype.indexOf采用了===进行比较,而includes采用了SameValueZero()进行比较,这是引擎内置的比较方式,没有对外接口,其实现采用了Map和Set,最直接的好处就是可以判断NaN。
[NaN].includes(NaN) // true [NaN].indexOf(NaN) // -1
-
Object.spread和Object.assign
{…obj}和Object.assign({}, obj)是等价的,但是还存在区别。Object.assign会修改第一个参数对象,这个修改可以触发其第一个参数对象的settter。Object.spread会创建一个对象副本,而不会修改任何值。虽然保证assign第一个参数为空对象,也能实现同样的不可变性,但性能相对差很多。
-
箭头函数不适用场景
构造函数的原型方法需要通过this获得实例,因此箭头函数不可以出现在构造函数的原型方法上。
const person = { name: 'jack', getName: () => { console.log(this.name) } } person.getName()
getName函数内的this指向window,并不符合使用场景。
const btn = document.getElementById('btn') btn.addEventListener('click', () => { console.log(this === window) })
事件绑定函数内的this指向了window,无法获取事件对象。
-
proxy代理
class Person { constructor(name) { this.name = name } } let proxyPerson = new Proxy(Person, { apply(target, context, args) { throw new Error('error') } })
对Person构造函数进行了代理,防止它作为非构造函数被调用。
proxyPerson('jack') // Uncaught Error new proxyPerson('jack') // {name: 'jack'}
也可以改造成不使用new关键字调用:
let proxyPerson = new Proxy(Person, { apply(target, context, args) { return new (target.bind(context, ...args))() } })
-
assert断言
assert['error msg'] = boolean
当右侧表达式不成立时,抛出错误。
可以通过拦截assert对象的赋值操作实现:const assert = new Proxy({}, { set(target, warning, value) { if (!value) { console.log(warning) } } })
-
decorator装饰器
装饰器就是给类添加或修改属性与方法的。
在对象方法中给普通函数赋值后,在全局作用域下被调用时this指向会丢失,指向了window,可以使用autobind完成对this的绑定。class Person { constructor(name) { this.name = name } @autobind getName() { return this.name } }
2.babel编译
babel最核心的功能是:编译ES Next代码,进行降级处理,进而规避兼容性问题。核心原理是使用AST(抽象语法树)对源码进行分析并转为目标代码。
-
const、let都会被编译为var,babel在编译过程中发现对const声明的变量二次赋值会直接报错。对块级作用域,在块内给变量换一个名字,这样在块外自然无法被访问到了。
-
对于for循环,babel使用闭包来储存变量。
-
箭头函数中会将当前环境下的this保存为新的变量,在调用方法时用新存储的this替换函数体内的this。