ECMAScript6中的Class

本质上,ES6只是ES5的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性,Class和let一样,不存在变量提升。ES6实现了类的继承,类的静态方法,但是目前没有规定类的静态属性,在ES7中,有关于静态属性的提议。

Class类基础

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//ES5的写法
function Point(x,y){
this.x = x;
this.y = y;
}

Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
}

//ES6的写法
Class Point { //其实它可以看做构造函数的另一种写法。
constructor(x, y) {
this.x = x; //显示定义在本身,而不是原型上
this.y = y;
}
toString() { //class这种写法,方法是不可枚举的
return '(' + this.x + ', ' + this.y + ')';
}
}

Class的继承

Class之间可以通过extends关键字实现继承。ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

1
2
3
4
5
6
7
8
9
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color; //this是继承父类的this对象,然后对其进行加工
}
toString() {
return this.color + ' ' + super.toString(); // super代表父类实例,调用父类的toString()
}
}

类的prototype和proto属性

大多数浏览器的ES5实现之中,每一个对象都有proto属性,指向对应的构造函数的prototype属性。Class作为构造函数的语法糖,同时有prototype属性和proto属性,因此同时存在两条继承链。一、子类的proto属性,表示构造函数的继承,总是指向父类。二、子类prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性。

1
2
3
4
class A {}
class B extends A {}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true

Class的静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。父类的静态方法,可以被子类继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod() //typeeror static方法不会被实例继承

Class Bar extends Foo{
static classMethod() {
return super.classMethod()+'too'; //可以从super对象上调用
}
}
Bar.classMethod() //'hello' static方法可以被子类继承,