類別

ES6 在 JavaScript 中引入「類別」的概念,與其他程式設計語言的類別不同。這裡的類別是特殊函式,可做為範本使用,用來建立已含有資料的物件、與該資料相關聯的屬性,以及與這些資料操控相關的方法。這些物件、屬性和方法統稱為類別的「成員」。

若要定義類別,請使用 class 關鍵字。按照 JavaScript 內建建構函式函式製定的最佳做法和慣例,為類別的任何 ID 以大寫字母開頭:

class MyClass {}

類別旨在提供更易於存取的方式,以便處理原型和建構函式函式的進階功能:

class MyClass {}

typeof MyClass;
> "function"

由於類別已部分新增,使使用進階 JavaScript 功能更容易使用,也更吸引人,因此有時也稱為「語法糖」。不過,類別除了能針對原型繼承作業提供實用的簡短資訊,隆重推出類別語法創造機會,解決 JavaScript 長期以來的設計問題,而且不會導入回溯相容性問題。舉例來說,類別主體中的所有程式碼一律會以嚴格模式評估。

如要建立類別的執行個體,請使用 new 運算子。

class MyClass {}

const myClassInstance = new MyClass();

myClassInstance;
> Object { }

類別主體中定義的函式會以該類別每個例項的方法公開。

class MyClass {
    classMethod() {
        console.log( "My class method." );
    }
}

const myClassInstance = new MyClass();

myClassInstance.classMethod();
> "My class method."

類別中定義的方法會成為結果例項原型上的方法。由於原型鏈具有性質,您可以直接對產生的物件呼叫這些方法:

class MyClass {
  classMethod() {
    console.log( "My class method." );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { }
    <prototype>: Object { … }
        classMethod: function classMethod()
        constructor: class MyClass { constructor(myPassedValue) }
        <prototype>: Object { … }

myClassInstance.classMethod();
> "My class method."

建立類別的執行個體會呼叫特殊的 constructor() 方法,對新建立的執行個體執行所有必要的「設定」,並初始化相關聯的所有屬性。建立執行個體時,傳送至該類別的任何引數都可以提供給 constructor() 方法:

class MyClass {
  constructor( myPassedValue ) {
    console.log( myPassedValue );
  }
}

const myClassInstance = new MyClass( "A string." );
> "A string."

在類別主體中,this 的值是指執行個體本身,而 this 中定義的任何屬性都會公開為該類別各例項的屬性:

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProperty = myPassedValue;
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { instanceProperty: "A string." }

這些屬性也能提供給類別主體中的所有方法:

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProp = myPassedValue;
  }
  myMethod() {
    console.log( this.instanceProp );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance.myMethod();
> "A string."

如果您未為類別定義 constructor(),JavaScript 引擎會假設空白的「預設」constructor。每個類別只能有一個名為 constructor() 的特殊方法:

class MyClass {
  constructor() {}
  constructor() {}
}
> Uncaught SyntaxError: A class may only have one constructor

您可以使用「類別宣告」或「類別運算式」來定義類別。先前的範例全都是類別宣告,因此必須使用 new 叫用名稱。類別運算式可以或不命名,建立「匿名」類別。

let ClassExpression = class {
    constructor() {}
};

ClassExpression;
> class  {}

您可以將匿名類別運算式用於「即時」建構類別的函式:

function classMaker() {
  return class {
    constructor() {}
  };
}

let MyVariable = classMaker();

MyVariable;
> class  {}

使用類別宣告重新宣告類別會導致語法錯誤:


class MyClass {
    constructor( ) {
        console.log( "My class." );
    }
};

class MyClass {
    constructor() {
        console.log( "My new class." );
    }
};
> Uncaught SyntaxError: redeclaration of class MyClass

不過,類別運算式可讓您重新定義類別:

let ClassExpression = class MyClass { };

ClassExpression = class MyOtherClass {
    constructor( myString ) {
        this.myProp = myString;
    }
};

new ClassExpression( "String." );
> MyOtherClass {myProp: 'String.'}

您無法以類別宣告的方式叫用已命名的類別運算式。不過,系統會將類別運算式的指派名稱當做已建立執行個體的屬性來使用,這主要是簡化偵錯作業:

let MyVariable = class MyClass {};

MyClass;
> Uncaught ReferenceError: MyClass is not defined

MyVariable;
> class MyClass {}

MyVariable.name;
> "MyClass"

使用類別運算式初始化變數時,系統會如預期遵循該變數的提升規則。類別宣告遵循letconst 相同的「暫時無效區域」規則,且行為會像是未提升至目前範圍的頂部,這表示在類別宣告之前叫用類別會導致錯誤:

{
    let myVar = new MyClass( "Property string." );

    class MyClass {
        myProp;

        constructor( myString ) {
            this.myProp = myString;
        }
    };
};
> Uncaught ReferenceError: Cannot access 'MyClass' before initialization

隨堂測驗

以下何者正確定義類別?

class MyClass {}
myClass = class {}
new class()

一個類別可以有多少個 constructor() 方法?

一個
無上限