1、简介
类Class 可以通过extends
关键字实现继承,让子类继承父类的属性和方法。extends 的写法比 ES5 的原型链继承,要清晰和方便很多。
class Foo {constructor(x, y) {this.x = x;this.y = y;console.log('父类构造函数')}toString() {return '(' + this.x + ', ' + this.y + ')';}
}class Baroo extends Foo {constructor(x, y, color) {this.color = color; // ReferenceError super(x, y)之后才能使用子类thissuper(x, y); // 调用父类的constructor(x, y) 目的是新建子类实例this.color = color;console.log(x,y,color)console.log('子类构造函数')}toString() {return this.color + ' ' + super.toString(); // 调用父类的toString()}
}let baroo = new Baroo(1,2,'#ffffff') // 1,2,'#ffffff'
console.log(baroo) //Baroo {x: 1, y: 2, color: '#ffffff'}
console.log(baroo.toString()) // #ffffff (1, 2)
上面示例中,constructor()
方法和toString()
方法内部,都出现了super
关键字。super
在这里表示父类的构造函数,用来新建一个父类的实例对象
ES6 规定,子类必须在constructor()
方法中调用super()
,否则就会报错。这是因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。如果不调用super()
方法,子类就得不到自己的this
对象。
注意,这意味着新建子类实例时,父类的构造函数必定会先运行一次。
上面示例中,子类 Bar 新建实例时,会输出 "父类构造函数","子类构造函数"。原因就是子类构造函数调用super()
时,会执行一次父类构造函数(并在调用super()后才能使用子类的this,否则会报错)
// 如果子类没有定义constructor()方法,这个方法会默认添加,并且里面会调用super()。
// 也就是说,不管有没有显式定义,任何一个子类都有constructor()方法。class ColorPoint extends Point {}// 等同于
class ColorPoint extends Point {constructor(...args) {super(...args);}
}
2、super关键字
super
这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super
作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super()
函数。
class Foo {}class Boo extends Foo {constructor() {super();}
}//子类B的构造函数之中的super(),代表调用父类的构造函数。这是必须的,否则报错
注意,这里的super
虽然代表了父类的构造函数,但是因为返回的是子类的this
(即子类的实例对象),所以super
内部的this
代表子类的实例,而不是父类的实例,这里的super()
相当于A.prototype.constructor.call(this)
(在子类的this
上运行父类的构造函数)。
class A {constructor() {console.log(new.target.name);}
}
class B extends A {constructor() {super();}
}
new A() // A
new B() // B
上面示例中,new.target
指向当前正在执行的函数。可以看到,在super()
执行时(new B()
),它指向的是子类B
的构造函数,而不是父类A
的构造函数。
ES6 规定,在子类普通方法中通过super
调用父类的方法时,方法内部的this
指向当前的子类实例,也就是说,super()
内部的this
指向的是B。
3、类的prototype属性和__proto__属性
在之前ES5实现中,每个对象都有__proo__属性,指向对应的构造函数的prototype属性。
ES6中类Class 作为构造函数的语法糖,同时有prototype
属性和__proto__
属性,因此同时存在两条继承链。
(1)子类的
__proto__
属性,表示构造函数的继承,总是指向父类。(2)子类
prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。
class A {}class B extends A {
}B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true