類別欄位和方法

欄位

類別欄位是直接在類別主體中宣告,不會明確新增為 this 值的屬性。但結果是相同的:在該類別的執行個體上定義的屬性。

class MyClass {
    myField;
}

const myClassInstance = new MyClass();

myClassInstance;
> MyClass { myField: undefined }

您可以使用值來初始化欄位。通常這是類別內的邏輯可以覆寫的預設值:

class MyClass {
    myResult = false;
    set setValue( myValue ) {
        this.myResult = myValue;
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> Object { myResult: false }

myClassInstance.setValue = true;

myClassInstance;\
> Object { myResult: true }

類別欄位功能與使用 this 附加至類別的屬性相同。也就是說,您可以在類別外存取及修改這些屬性,就像任何其他屬性一樣。

class MyClass {
    myField = true;
}

const myClassInstance = new MyClass();

myClassInstance.myField;
> true

myClassInstance.myField = false;

myClassInstance.myField;
> false;

欄位是類別一些更進階功能的基礎。

私人欄位和方法

不公開欄位和方法無法在類別外存取。私人屬性會與類別的執行個體相關聯,這表示每個執行個體都包含一組在類別中定義的私人欄位和方法。

如要將屬性設為不公開,請在宣告時,於 ID 開頭加上 #

class MyClass {
    #myPrivateField = true;
    #myPrivateMethod() {}
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass { #myPrivateField: true }
    #myPrivateField: true
    <prototype>: Object { … }
        constructor: class MyClass {}
        <prototype>: Object { … }

不公開欄位必須在所屬類別的主體中宣告。您之後可以將其值修改為 this 的屬性,但無法使用 this 建立該欄位。

您無法從指令碼的其他位置存取私人欄位。這樣可以防止在 getter 和 setter 方法外,變更資料屬性以與所含的值互動,並防止直接存取只能在類別內部使用的方法。

class MyClass {
    #myResult = false;
    set setValue( myValue ) {
        this.#myResult = myValue;
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass { #myResult: false }

myClassInstance.#myResult = true;
> Uncaught SyntaxError: reference to undeclared private field or method #myResult

myClassInstance.setValue = true;

myClassInstance;\
> MyClass { #myResult: true }

不過請注意,瀏覽器的開發人員控制台一般來說非常寬鬆,但不一致是禁止存取私人欄位並進行偵錯:

class MyClass {
    #myPrivateField = true;
    #myPrivateMethod() {
        console.log( "This is inside a private method." );
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass {#myPrivateField: true}

myClassInstance.#myPrivateField;
> true

myClassInstance.#myPrivateMethod();
> "This is inside a private method."
class MyClass {
    #myPrivateField = true;
    #myPrivateMethod() {
        console.log( "This is inside a private method." );
    }
}
const myClassInstance = new MyClass();

myClassInstance;
> MyClass {#myPrivateField: true}

myClassInstance.#myPrivateField;
> Uncaught SyntaxError: reference to undeclared private field or method #myPrivateField

myClassInstance.#myPrivateMethod();
> Uncaught SyntaxError: reference to undeclared private field or method #myPrivateMethod

私人欄位的範圍限定為包含這些欄位的類別主體,因此即使是子項類別也無法存取與父項類別相關聯的不公開欄位:

class MyClass {
    #myPrivateField = true;
}
class ChildClass extends MyClass {
    childMethod() {
        console.log( this.#myPrivateField );
    }
}
> Uncaught SyntaxError: reference to undeclared private field or method #myPrivateField

靜態欄位和方法

靜態欄位和方法是類別本身的成員,而非該類別的執行個體成員。因此,對於類別的每個執行個體而言,靜態欄位可提供集中的資料中心點,但這些執行個體可能需要參照,例如共用設定資訊。靜態方法通常是公用函式,用於處理類別的執行個體,例如將例項與所含欄位進行比較或排序。

如要在類別主體中定義靜態欄位和方法,請使用 static 關鍵字:

class MyClass {
    static myStaticField;
    static myStaticMethod() {}
}
const myClassInstance = new MyClass();

您也可以使用點標記法建立靜態方法:

class MyClass {
    constructor() {}
}
MyClass.myStaticMethod = function() {}

您無法從類別的執行個體存取靜態屬性,但您可以在類別建構函式上使用這些屬性:

class MyClass {
    static myStaticField = true;
    static myStaticMethod() {
        console.log( "A static method." );
    }
}
const myClassInstance = new MyClass();

myClassInstance.myStaticField;
> undefined

myClassInstance.myStaticMethod();
> Uncaught TypeError: myClassInstance.myStaticMethod is not a function

MyClass.myStaticField;
> true

MyClass.myStaticMethod();
> "A static method."

技術上不一定要使用,但靜態方法是建立與類別執行個體搭配使用的公用程式的最佳做法。例如用於排序類別執行個體的靜態方法,或是靜態工廠方法 (包含建立類別執行個體所需的任何設定),然後傳回該類別例項:

class User {
    constructor( name, email ) {
        this.name = name;
        this.email = email;
    }
    static fromObject( myObject ) {
        return new User( myObject.name, myObject.email ?? "Omitted" );
    }
}
const userObject = {
    "name" : "My Name",
    "email" : "my@email.address"
};
const secondUserObject = {
    "name" : "My Name"
};

const firstUser = User.fromObject( userObject );
const secondUser = User.fromObject( secondUserObject );

firstUser;
> Object { name: "My Name", email: "my@email.address" }

secondUser;
> Object { name: "My Name", email: "Omitted" }

隨堂測驗

以下哪種類型的欄位只能從類別內部存取?

不公開欄位
類別欄位
Static fields