ES6引入了Class(类)这个概念,做为对象的模板。经过class
关键字,能够定义类。基本上,ES6的class
能够看做只是一个语法糖,它的绝大部分功能,ES5均可以作到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。编程
ES6的类,彻底能够看做构造函数的另外一种写法。浏览器
类的数据类型就是函数,类自己就指向构造函数。app
使用的时候,也是直接对类使用new
命令,跟构造函数的用法彻底一致。函数
constructor
方法是类的默认方法,经过new
命令生成对象实例时,自动调用该方法。一个类必须有constructor
方法,若是没有显式定义,一个空的constructor
方法会被默认添加。类的构造函数,不使用new
是无法调用的,会报错。这是它跟普通构造函数的一个主要区别,后者不用new
也能够执行。this
生成类的实例对象的写法,与ES5彻底同样,也是使用new
命令。若是忘记加上new
,像函数那样调用Class
,将会报错。spa
与ES5同样,实例的属性除非显式定义在其自己(即定义在this
对象上),否则都是定义在原型上(即定义在class
上)。prototype
x
和y
都是实例对象point
自身的属性(由于定义在this
变量上),因此hasOwnProperty
方法返回true
,而toString
是原型对象的属性(由于定义在Point
类上),因此hasOwnProperty
方法返回false
。这些都与ES5的行为保持一致。3d
Class不存在变量提高(hoist),这一点与ES5彻底不一样。code
上面代码中,Foo
类使用在前,定义在后,这样会报错,由于ES6不会把类的声明提高到代码头部。这种规定的缘由与下文要提到的继承有关,必须保证子类在父类以后定义。对象
Class的继承
Class之间能够经过extends
关键字实现继承,这比ES5的经过修改原型链实现继承,要清晰和方便不少。
上面代码定义了一个ColorPoint
类,该类经过extends
关键字,继承了Point
类的全部属性和方法。可是因为没有部署任何代码,因此这两个类彻底同样,等于复制了一个Point
类
constructor
方法和toString
方法之中,都出现了super
关键字,它在这里表示父类的构造函数,用来新建父类的this
对象。
子类必须在constructor
方法中调用super
方法,不然新建实例时会报错。这是由于子类没有本身的this
对象,而是继承父类的this
对象,而后对其进行加工。若是不调用super
方法,子类就得不到this
对象。
ES5的继承,实质是先创造子类的实例对象this
,而后再将父类的方法添加到this
上面(Parent.apply(this)
)。ES6的继承机制彻底不一样,实质是先创造父类的实例对象this
(因此必须先调用super
方法),而后再用子类的构造函数修改this
。
另外一个须要注意的地方是,在子类的构造函数中,只有调用super
以后,才可使用this
关键字,不然会报错。这是由于子类实例的构建,是基于对父类实例加工,只有super
方法才能返回父类实例。
大多数浏览器的ES5实现之中,每个对象都有__proto__
属性,指向对应的构造函数的prototype属性。Class做为构造函数的语法糖,同时有prototype属性和__proto__
属性,所以同时存在两条继承链。
(1)子类的__proto__
属性,表示构造函数的继承,老是指向父类。
(2)子类prototype
属性的__proto__
属性,表示方法的继承,老是指向父类的prototype
属性。
上面代码中,子类B
的__proto__
属性指向父类A
,子类B
的prototype
属性的__proto__
属性指向父类A
的prototype
属性。
这样的结果是由于,类的继承是按照下面的模式实现的。
Object.setPrototypeOf
方法的实现:
故上面代码等同于这里的代码
这两条继承链,能够这样理解:
做为一个对象,子类(B
)的原型(__proto__
属性)是父类(A
);做为一个构造函数,子类(B
)的原型(prototype
属性)是父类的实例。