跳轉到內容

JavaScript/OOP-類

來自華夏公益教科書,開放的書籍,為開放的世界



面向物件程式設計中基於類的程式語言的流行程度激勵了 JavaScript 社群,他們用模仿基於類的程式設計方法的語法來覆蓋其基於原型的 OOP 實現。EcmaScript 2015 (ES6) 透過相應的關鍵詞(如“class”或“extend”)得到了擴充套件。

類是用於建立物件的模板或“藍圖”。它們封裝了它們的資料,幷包含用於處理資料的函式。

class Person {
  // Class body is always implicitly in "use strict" mode
  constructor(name) {
    // Data. Declarations like 'let x = 0' are not necessary.
    this.name = name;
  }
  // functionality
  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
alert(ada.showName());

關鍵字 class 引入類定義。在示例中,Person 是類名。它後面跟著用花括號 { }(第 1 行到第 11 行)括起來的類主體。在主體內部,有一個特殊方法 constructor。此函式在類建立期間被呼叫。在示例中,它接受一個引數,即一個人的姓名。在 constructor 內部,此引數使用關鍵字“this”在內部儲存。該類只提供一個功能:showName 方法。

靜態屬性和方法

[編輯 | 編輯原始碼]

上面的語法顯示瞭如何處理單個物件(例項 - 就像上面示例中的“ada”)的屬性和方法。還可以定義在單個物件級別不可用但在類級別可用的屬性和方法 - 上述示例中的“Person”。它們由關鍵字 static 引入。

class Person {
  constructor(name) {
    // data
    this.name = name;
  }

  static className = "The PERSON Class";
  static showClassName() {return "The name of this class is: " + this.className};

  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
// alert(ada.showClassName()); // Error!
alert(Person.showClassName());

第 7 行和第 8 行使用“static”關鍵字。因此,屬性和方法不適用於例項,而只適用於整個類。

類方法可以作為屬性提供。這使程式設計師能夠區分透過圓括號 () 訪問方法和屬性。關鍵字 get 引入此功能。

class Person {
  constructor(name) {
    this.name = name;
  }
  // getter
  get showTheName() {
    return this.showName();
  }
  // 'regular' method
  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
// NO parenthesis ()
alert(ada.showTheName);

接下來,我們定義一個類層次結構。這是使用關鍵字 extends 完成的。在示例中,EmployeePerson 的子類,並且可以訪問其所有屬性和方法。

class Person {
  constructor(name) {
    this.name = name;
  }
  // method
  showName() {
    return "My name is: " + this.name;
  }
}
class Employee extends Person {
  constructor(name, company) {
    super(name);
    this.company = company;
  }
  // method
  showCompany() {
    return "I, " + this.name + ", work at the company " + this.company;
  }
}

const henry = new Employee("Henry Miller", "ACME Inc.");
alert(henry.showCompany());
alert(henry.showName());     // method of the parent class

第 12 行呼叫父類的建構函式。這是必要的,因為父類的 constructor 建立“this”。

訪問控制

[編輯 | 編輯原始碼]

預設情況下,類屬性和方法是可訪問的。您可以使用井號 # 作為它們名稱的第一個字元來隱藏它們。

class Person {

  // two hidden properties (sometimes called 'private fields')
  #firstName;
  #lastName;

  constructor(firstName, lastName) {
    this.#firstName = firstName;
    this.#lastName = lastName;
    // one public property
    this.name = lastName + ", " + firstName;
  }
  #showName() {  // hidden method
    alert("My name is " + this.name);
  }
}

const ada = new Person("Ada", "Lovelace");
alert(ada.name);        // ok
alert(ada.firstName);   // undefined
alert(ada.#firstName);  // undeclared private field

alert(ada.#showName()); // undeclared private method

多型性

[編輯 | 編輯原始碼]

如果方法名在“父”類和“子”類中都被使用,JavaScript 引擎將呼叫相關類的那個方法。

class Person {
  constructor(name) {
    this.name = name;
  }
  // method name is used also in 'child'
  showName() {
    return "My name is: " + this.name;
  }
}
class Employee extends Person {
  constructor(name, company) {
    super(name);
    this.company = company;
  }
  // same method name as in 'parent'
  showName() {
    return "My name is: " + this.name + ". I'm working at the company " + this.company;
  }
}

const henry = new Employee("Henry Miller", "ACME Inc.");
alert(henry.showName());       // from Employee

const nextPerson = new Person("John");
alert(nextPerson.showName());  // from Person

示例定義並使用兩個不同的方法 showName

this 不是變數或物件;它是一個關鍵字。根據上下文,它指的是不同的東西。在類定義的上下文中,它指的是類本身,例如,this.city = "Nairobi" 指的是當前類的屬性“city”。

this 在檔案的最頂層使用時(換句話說,在任何函式或物件之外),它指的是全域性物件。在嚴格模式下,在函式中,this 為 undefined。在 DOM 事件中,它指的是接收事件的元素。

… 在另一個頁面上提供(點選此處)。
華夏公益教科書