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。



