JavaScript 類的附加特性

JavaScript 類的附加特性

在本文中,我們將解釋 JavaScript 中類的附加特性。

YouTube Video

JavaScript 類的附加特性

JavaScript 中的私有屬性

在 JavaScript 中,私有屬性是只能在物件或類內部訪問的屬性。它通過提供封裝實現了更安全和穩健的代碼設計,防止外部代碼直接修改或引用。

在 2020 年推出的 ECMAScript 2020(ES11)中,引入了使用「#」來定義類別中的私有字段。這種方式比傳統的 JavaScript 私有慣例(例如,以底線開頭的變數名稱)更加明確。這提供了一種更清晰的方法,取代了傳統的 JavaScript 私有慣例(例如變量名以下劃線開頭)。

如何使用私有屬性

在類中定義私有屬性

私有字段是使用以 # 開頭的名稱來定義的。此字段不能直接從類的實例或其子類中訪問。

 1class Person {
 2    // Define private property
 3    #name;
 4
 5    constructor(name) {
 6        this.#name = name;
 7    }
 8
 9    // Method to access the private property
10    getName() {
11        return this.#name;
12    }
13
14    // Method to change the private property
15    setName(newName) {
16        this.#name = newName;
17    }
18}
19
20const john = new Person("John");
21console.log(john.getName()); // John

在上述代碼中,#name 是一個私有屬性,無法從 Person 類的外部直接訪問。只能通過 getNamesetName 方法訪問或更改名稱。

1// Cannot access private property directly
2console.log(john.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class

定義私有方法

與私有屬性一樣,私有方法也是使用以 # 開頭的名稱進行定義的。私有方法只能從類內部調用。

 1class Counter {
 2    #count = 0;
 3
 4    increment() {
 5        this.#count++;
 6        this.#logCount(); // Calling private method
 7    }
 8
 9    // Private method
10    #logCount() {
11        console.log(`Current count: ${this.#count}`);
12    }
13}
14
15const counter = new Counter();
16counter.increment(); // Current count: 1

在這裡,#logCount 被定義為一個私有方法,不能從類外訪問。此方法僅在類內使用。

1// Cannot access private method directly
2counter.#logCount(); // SyntaxError: Private field '#logCount' must be declared in an enclosing class

私有屬性的優勢和注意事項

優勢

  • 封裝:隱藏內部狀態,不對外暴露,並維持數據一致性。
  • 安全性:防止屬性被外部代碼意外修改。
  • 提高可維護性:隱藏物件或類的實現,並明確對外暴露的介面。

注意事項

  • 由於私有字段在類外部完全隱藏,測試和調試可能會變得困難。因此,在設計階段提供一個可以徹底測試的 API 是很重要的。
  • 私有字段的行為與具有基於原型特性的其他 JavaScript 部分不同,因為它們對每個實例都是唯一的。

傳統的私有屬性偽實現

在引入使用 # 的私有字段之前,JavaScript 並沒有正式的私有屬性語法。因此,在過去,偽私有屬性是通過以下方式實現的。

使用底線的慣例

開發人員慣例上通過在變量名稱前添加底線前綴來表示“私有”。

 1class Car {
 2    constructor(brand) {
 3        this._brand = brand; // Using an underscore to indicate private
 4    }
 5
 6    getBrand() {
 7        return this._brand;
 8    }
 9}
10
11const car = new Car("Toyota");
12console.log(car.getBrand()); // Toyota
13console.log(car._brand); // Toyota (Accessible from outside)

這種方法僅僅是一種“慣例”,實際上屬性仍然可以從外部訪問。

使用閉包實現私有屬性

也可以通過使用具有函數作用域的閉包來實現私有屬性。

 1function createPerson(name) {
 2    let _name = name; // Private variable within function scope
 3
 4    return {
 5        getName: function() {
 6            return _name;
 7        },
 8        setName: function(newName) {
 9            _name = newName;
10        }
11    };
12}
13
14const person = createPerson("Alice");
15console.log(person.getName()); // Alice
16person.setName("Bob");
17console.log(person.getName()); // Bob
18
19// Cannot access directly from outside
20console.log(person._name); // undefined

通過這種方法,變量 _name 被封裝在函數作用域內,無法從外部直接訪問。

總結

JavaScript 中的私有屬性在類和對象設計中提供封裝非常有效,有助於安全地保護數據。ES2020 中引入的使用 # 表示私有字段的方法,與傳統的慣例和閉包相比,提供了一種更清晰且更安全的隱私管理方法。

JavaScript 中的可選鏈接

選擇鏈(Optional chaining)是 JavaScript 中一個非常有用的語法,用於存取深層巢狀的物件屬性。它通過允許安全訪問而無需單獨檢查特定屬性的存在,提高了代碼的可讀性和可維護性。

可選鏈接的基本語法

選擇鏈可以在用於屬性存取的「.」或中括號之前加上「?」來使用。當遍歷的屬性為 nullundefined 時,此符號返回 undefined,允許程序安全地繼續處理而不拋出錯誤。

範例:

 1const user = {
 2    name: 'John',
 3    address: {
 4        street: '123 Main St',
 5        city: 'New York'
 6    }
 7};
 8
 9// Without using optional chaining
10const city = user && user.address && user.address.city;
11console.log(city);  // New York
12
13// Using optional chaining
14const cityWithOptionalChaining = user?.address?.city;
15console.log(cityWithOptionalChaining);  // New York

在此示例中,我們訪問的是 user 對象的 address 及其 city 屬性。如果不使用可選鏈接,您需要進行多次存在檢查,但使用可選鏈接,您可以通過一條語句安全地訪問屬性。

在陣列和函數中使用可選鏈接

可選鏈接不僅適用於對象屬性,還適用於陣列元素和函數調用。

陣列範例:

1const users = [{ name: 'Alice' }, { name: 'Bob' }];
2
3// Accessing the non-existent third element
4const thirdUser = users[2]?.name;
5console.log(thirdUser);  // undefined
  • 這樣,你也可以使用可選鏈取(optional chaining)來存取陣列元素。

函數範例:

 1const user = {
 2    greet: function() {
 3        return 'Hello!';
 4    }
 5};
 6
 7// Call the function only if greet exists
 8const greeting = user.greet?.();
 9console.log(greeting);  // Hello!
10
11// Return undefined if greet does not exist
12const nonExistentGreeting = user.nonExistentMethod?.();
13console.log(nonExistentGreeting);  // undefined
  • 如本範例所示,它也可以應用於函式呼叫。

將可選鏈接與默認值結合使用

使用可選鏈接時,當屬性不存在時,通常使用邏輯或運算符(||)或空合併運算符(??)設置默認值。

範例:

 1const user = {
 2    name: 'John',
 3    address: {
 4        city: 'New York'
 5    }
 6};
 7
 8// Set a default value for a non-existent property
 9const state = user?.address?.state || 'Unknown';
10console.log(state);  // Unknown
11
12// Example using the nullish coalescing operator
13const zipCode = user?.address?.zipCode ?? '00000';
14console.log(zipCode);  // 00000

邏輯或運算子(OR operator)會將 false0'' 等值視為 falsy,而空值合併運算子(nullish coalescing operator)僅在值為 nullundefined 時才會使用預設值。

可選鏈接的優點

  • 安全訪問嵌套對象:通過使用可選鏈接,您無需再執行顯式的存在檢查,使代碼更加簡潔。
  • 避免錯誤:即使屬性是 nullundefined,它也可以防止運行時錯誤。
  • 提升可讀性和維護性:特別是在處理多個嵌套對象時,代碼的可讀性將大幅提高。

使用可選鏈接的注意事項

  • 頻繁使用可選鏈接可能表明數據結構的設計過於複雜。您應該努力實現一個簡單的數據模型。
  • 由於某些舊版瀏覽器和JavaScript引擎不支持此功能,您可能需要使用polyfill或轉譯器。

結論

可選鏈接是一個強大的功能,能夠簡化對JavaScript中嵌套對象的屬性和函數的安全訪問。在訪問深度嵌套數據結構時,它特別有效,有助於防止錯誤並提升代碼的可讀性。

您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。

YouTube Video