目錄
- 簡介
- Object.getPropertyOf()
- super 關鍵字
1、簡介
class 可以通過
extends
關鍵字實作繼承。
在子類繼承父類的時候,在
constructor
中必須首先調用
super()
方法,然後才能使用
this
。
// 父類
class Point {
constructor (x){
this.x = x;
}
toString(){
console.log('這種顔色耐髒!');
}
}
// 子類
class ColorPoint extends Point {
constructor(x, color){
// 必須首先調用父類的constructor(x)
super(x);
this.color = color;
}
toString(){
// 調用父類的toString()
return this.color + ' ' + super.toString();
}
}
子類必須在
constructor
方法中調用
super
方法,否則建立執行個體時會報錯。這是因為子類自己的
this
對象,必須先通過父類的構造函數完成塑造,得到與父類同樣的執行個體屬性和方法,然後再對其進行加工,加上子類自己的執行個體屬性和方法。如果不調用
super
方法,子類就得不到
this
對象。
ES5 的繼承,實質是先創造子類的執行個體對象
this
,然後再将父類的方法添加到
this
上面(Parent.apply(this))。ES6 的繼承機制完全不同,實質是先創造父類的執行個體對象
this
(是以必須先調用
super
方法),然後再用子類的構造函數修改
this
。
父類的靜态方法,也會被子類繼承。
class A {
static hello(){
console.log('hello world');
}
}
class B extends A {
}
B.hello() // hello world
上面代碼中,
hello()
是
A
類的靜态方法,
B
繼承
A
,也繼承了
A
的靜态方法。
2、Object.getPrototypeOf()
Object.getPrototypeOf
方法可以用來從子類上擷取父類。
Object.getPrototypeOf(ColorPoint) === Point
// true
是以,可以使用這個方法判斷,一個類是否繼承了另一個類。
3、super 關鍵字
super
這個關鍵字,既可以當作函數使用,也可以當作對象使用。
第一種情況,
super
作為函數調用時,代表父類的構造函數。
class A {}
class B extends A {
constructor() {
super();
}
}
第二種情況,
super
作為對象時,在普通方法中,指向父類的原型對象;在靜态方法中,指向父類。
class A {
p() {
return ;
}
}
class B extends A {
constructor() {
super();
console.log(super.p()); // 2
}
}
let b = new B();
上面代碼中,子類
B
當中的
super.p()
,就是将
super
當作一個對象使用。這時,
super
在普通方法之中,指向
A.prototype
,是以
super.p()
就相當于
A.prototype.p()
。
這裡需要注意,由于
super
指向父類的原型對象,是以定義在父類執行個體上的方法或屬性,是無法通過
super
調用的。
class A {
constructor(){
this.p = ; // p 為執行個體的屬性
}
}
class B extends A {
get m(){
return super.p;
}
}
let b = new B();
b.m // undefined
上面代碼中,
p
是父類
A
執行個體的屬性,
super.p
就引用不到它。
ES6 規定,在子類普通方法中通過
super
調用父類的方法時,方法内部的
this
指向目前的子類執行個體。
class A {
constructor (){
this.x = ;
}
print(){
console.log(this.x);
}
}
class B extends A {
constructor(){
super();
this.x = ;
}
m(){
super.print();
}
}
let b = new B();
b.m(); // 2
上面代碼中,
super.print()
雖然調用的是
A.prototype.print()
,但是
A.prototype.print()
内部的
this
指向子類
B
的執行個體,導緻輸出的是2,而不是1。也就是說,實際上執行的是
super.print.call(this)
。
如果
super
作為對象,用在靜态方法之中,這時
super
将指向父類,而不是父類的原型對象。
class Parent {
static myMethod(msg) {
console.log('static', msg);
}
myMethod(msg) {
console.log('instance', msg);
}
}
class Child extends Parent {
static myMethod(msg) {
super.myMethod(msg);
}
myMethod(msg) {
super.myMethod(msg);
}
}
Child.myMethod(); // static 1
var child = new Child();
child.myMethod(); // instance 2
上面代碼中,
super
在靜态方法之中指向父類,在普通方法之中指向父類的原型對象。
另外,在子類的靜态方法中通過
super
調用父類的方法時,方法内部的
this
指向目前的子類,而不是子類的執行個體。
class A {
constructor() {
this.x = ;
}
static print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = ;
}
static m() {
super.print();
}
}
B.x = ;
B.m() // 3
上面代碼中,靜态方法
B.m
裡面,
super.print
指向父類的靜态方法。這個方法裡面的
this
指向的是
B
,而不是
B
的執行個體。