天天看點

JS-學習ES6之- class 的繼承目錄1、簡介2、Object.getPrototypeOf()3、super 關鍵字

目錄

  • 簡介
  • 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

的執行個體。

繼續閱讀