Jun

只要我的心還會跳,腿還能動

我就沒有理由停下前進的步伐

Class 重點筆記


關於 Class

class 就是構造函數的語法糖,也可以說是構造函數的另一種寫法,使用時直接對 class 調用 new 即可:

class C1 {
  constructor(lastName, firstName) {
    this.lastName = lastName;
    this.firstName = firstName;
  }

  logName() {
    console.log(`My name is ${this.lastName} ${this.firstName}`);
  }
}

let c1 = new C1('Peng', 'Jing Jun');
c1.logName(); // My name is Peng Jing Jun

第一次學習 class 時雖然聽過它是構造函數的語法糖,但其實乍看之下還是挺不直覺的,所以這邊解剖一下上述代碼做了些什麼:

  1. 首先聲明了一個 C1class,換成構造函數的寫法就是 function C1 () {};

  2. class 內定義的方法最終都位於原型上,換成構造函數的寫法就是 C1.prototype.logName = function () {};

  3. constructor 方法就是構造函數,內部的 this 指向被 new 出來的實體

  4. constructorclass 的默認方法,通過 new 關鍵字生成的實體會自動調用 constructor 方法,即使沒有定義 constructor 也會默認產生一個空的 constructor

console.log(typeof C1); // function
console.log(C1 === C1.prototype.constructor); // true

構造函數的語法糖 class 只是讓原型的寫法更清晰、更像物件導向的語法而已

上述代碼說明了 class 的型別就是函數,而 class 本身就是指向構造函數

注意事項:


靜態方法

所有在 class 中定義的方法都會被實體繼承,如果不希望被繼承的話,在方法名前加上 static 關鍵字就表示該方法不會被實體繼承,而且直接通過 class 就可以調用:

class C1 {
  static helloWorld() {
    console.log('Hello World!');
  }
}

C1.helloWorld(); // Hello World!

const c1 = new C1();
c1.helloWorld(); // c1.helloWorld is not a function

上面說明了靜態方法可以直接於 class 上調用,而不是在 class 的實體上調用,如果在實體上調用的話就會噴錯,表示該方法並不存在

另外,父類別的靜態方法可以被子類別繼承:


繼承

JavaScript 類別使用 extends 關鍵字實現單繼承:

class Father {
  name;

  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

class Child extends Father {
  hello = 'Hello';
}

const res = new Child('Allen Iverson');

console.log(res.name); // Allen Iverson
console.log(res.getName()); // Allen Iverson
console.log(res.hello); // Hello

這段代碼 class Child extends Father {} 使得 Child 繼承 Father 的字段、方法以及構造函數

父類別的構造函數:constructor() 中的 super()

如果想在子類別中調用父類別的構造函數,需要在子類別的構造函數中使用 super() 方法:

class Father {
  name;

  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

class Child extends Father {
  hello = 'Hello';

  constructor(name, str) {
    super(name);
    this.hello = str;
  }
}

const res = new Child('Allen Iverson', 'Changed');

console.log(res.name); // Allen Iverson
console.log(res.getName()); // Allen Iverson
console.log(res.hello); // Changed

上述代碼中在子類別 Child 中的 super(name) 執行了父類別 Father 的構造函數

另外,在子類別構造函數中必須在使用 this 關鍵字之前調用 super() 方法,這樣才能確保父類別的構造函數完成初始化:

class Child extends Father {
  hello = 'Hello';

  constructor(name, str) {
    // ReferenceError ...
    this.hello = str;
    super(name);
  }
}
父類別實體:方法中的 super
class Father {
  name;

  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

class Child extends Father {
  constructor(name) {
    super(name);
  }

  getName() {
    const name = super.getName();
    if (name === '') {
      console.log('Empty');
    } else {
      console.log(name);
    }
  }
}

const res = new Child('');

res.getName(); // Empty

上述代碼中子類別 Child 中的 getName() 透過 super 訪問了父類別 Father 的方法 getName()

另外,也可以在靜態方法中使用 super 訪問父類別的靜態方法