Class
ES6中的Class写法只是让对象原型的写法更加清晰,更像面向对象编程 ( Object Oriented Programming,OOP ), 于构造函数用法完全一致。
1 | // ES5 |
this指向
1 | // 类的方法中的this默认指向类的实例,在外部调用类的方法时this指向可能会指向运行环境。 |
getter、setter
可使用get、set关键字对类内部的某个属性设置存值函数(setter)和取值函数(getter)
1 | class Myclass { |
class的静态方法
类相当于实例的原型,所有在类上定义的方法都会被实例继承,类的方法前加static关键字则不能被实例继承,只能通过类调用,称为“静态方法”。
1 | class Foo { |
class的静态属性和实例属性
静态属性是Class本身的属性,即Class.prop,而不是定义在实例对象this上的属性。
1 | // 实例属性 |
new.target属性
在class内部调用new.target属性,如果是通过new命令调用的会返回该类,如果不是则返回undefined
1 | class Foo { |
class继承
在ES5中继承实际是先创造子类的实例对象this,然后再将父类的方法添加到this上面。
在ES6中,子类在继承父类时实际上是继承父类的this对象,然后对其加工得到自己的this。必须在constructor中通过调用super方法,来调用父类的构造函数并新建父类的this对象,否则会报错。
1 | class Foo { |
类的prototype属性和proto属性
子类的proto属性标识构造函数的继承,总是指向父类
子类的prototype属性的proto属性表示方法的继承,总是指向父类的prototype
1 | class Foo { |
实例的__proto属性
子类实例的proto属性的proto属性指向父类实例的proto属性。即子类原型的原型是父类的原型。
1 | class Foo { |
Proxy
Proxy用于修改某些操作的默认行为,可以理解为在目标对象前架设了‘拦截层’,任何对该对象的操作都必须先通过Proxy。
1 | // target: 要拦截的目标对象。 |
实例方法:
get()
用于拦截某个属性的读取操作。
1 | let o = { |
set()
用于拦截某个属性的赋值操作。
1 | let proxy = new Proxy({}, { |
apply()
用于拦截函数调用、call、apply操作。
apply接受三个参数,目标对象、目标对象上下文(this)、目标对象参数数组
1 | let target = function(){ return "I am the target"} |
has()
1 |
Reflect
- 从Reflect对象上可以获取语言内部的方法
- 修改某些Object对象的返回结果,使其合理
- 让Object操作都变成函数行为
- 无论Proxy如何修改默认行为,都可以在Reflect上获取默认行为
静态方法
Reflect.get()
Promise
异步编程的一种解决方案,比传统的回调函数更合理更强大。
promise简单来说就是一个容器,里面保存着某个未来才会结束的事件的结果。
ES6规定promise对象是一个构造函数,用来生成promise实例。promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
1 | // promist构造函数接收一个函数作为参数,该函数接收两个函数resolve、reject作为参数。 |
Iterator 遍历器
为各种不同的数据结构提供的统一简便的访问接口(symbol.iterator),供for…of遍历使用。
1 | let arr = ['a', 'b']; |
原生具备iterator接口的数据接口:Array、Map、Set、String、arguments、NodeList对象。除此之外都需要自己手动在Symbol.iterator属性上面部署,才会被for…of遍历。
除了for…of,还有一些会默认调用Symbol.iterator接口的场合,比如:解构赋值、扩展运算符、yield*、Array.from()、Map()、Set()、WeakMap()、WeakSet()、Promise.all()、Promise.race()
iterator遍历过程
- 创建一个指针对象,指向当前数据的起始位置。
- 第一次调用指针对象的next方法,指针指向数据结构的第一个数据成员。
- 以此类推,直到指向数据结构的结束位置。
手动部署Symbol.iterator
1 | // class |
Generator
Generator 函数是 ES6 提供的一种异步编程解决方案。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。Generator 函数还是一个遍历器对象生成函数,可以使用for…of依次遍历 Generator 函数内部的每一个状态。
Generator与普通函数的区别在于需要在函数名前加*号,函数体内可以使用yield表达式,调用后不会直接执行,而是返回一个Iterator对象,调用该对象的next方法,直到遇到yield表达式或return为止。
1 | function* generator() { |
yield表达式
yield表达式是Generator函数暂停的标识,且具备位置记忆功能。
- 遇到
yield
表达式,就暂停执行后面的操作,并将紧跟在yield
后面的那个表达式的值,作为返回的对象的value
属性值。 - 下一次调用
next
方法时,再继续往下执行,直到遇到下一个yield
表达式或return
语句为止,并将return
语句后面的表达式的值,作为返回的对象的value
属性值。 - 如果该函数没有
return
语句,则返回的对象的value
属性值为undefined
。
如果在Generator函数内部需要调用另一个Generator函数或调用iterator接口的话可以使用yield*
表达式完成遍历。等同于在yield表达式后面部署了一个for…of循环。
1 | function* foo() { |
Generator函数应用
- 控制流管理
- 部署Iterator接口
- 作为数据结构
- 异步操作的同步化表达
- 异步应用(使用co模块做执行器)
async
Generator函数的语法糖,返回值为Promise,且自带执行器。
async函数返回一个Promise对象,必须等内部所有await执行完毕才会发生状态改变。如果await后面的异步操作出错,等同于async函数返回的Promise对象reject,最好使用try…catch包裹。
正常情况下await后面是一个Promise对象,返回该对象的结果,如果不是则直接返回。
注意:
1 | // 两个独立的异步操作(不互相依赖),被写成继发关系会比较耗时。 |
异步编程方法
- 回调函数
- 事件监听
- 发布/订阅
- Promise
- Generator
- async
Decorator 装饰器
类的装饰
在代码编译时,将类作为装饰器的第一个参数传入装饰器。可在类上添加静态属性或实例属性/方法。
1 | @decorator |
方法的装饰
方法的装饰器接收三个参数,类的原型对象、所要装饰的属性名、该属性的描述对象。
1 | class Person { |
注:由于存在函数提升,使得装饰器不能用于函数。类是不会提升的,所以就没有这方面的问题。