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 類的外部直接訪問。只能通過 getName 和 setName 方法訪問或更改名稱。
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 中一個非常有用的語法,用於存取深層巢狀的物件屬性。它通過允許安全訪問而無需單獨檢查特定屬性的存在,提高了代碼的可讀性和可維護性。
可選鏈接的基本語法
選擇鏈可以在用於屬性存取的「.」或中括號之前加上「?」來使用。當遍歷的屬性為 null 或 undefined 時,此符號返回 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)會將 false、0 和 '' 等值視為 falsy,而空值合併運算子(nullish coalescing operator)僅在值為 null 或 undefined 時才會使用預設值。
可選鏈接的優點
- 安全訪問嵌套對象:通過使用可選鏈接,您無需再執行顯式的存在檢查,使代碼更加簡潔。
- 避免錯誤:即使屬性是
null或undefined,它也可以防止運行時錯誤。 - 提升可讀性和維護性:特別是在處理多個嵌套對象時,代碼的可讀性將大幅提高。
使用可選鏈接的注意事項
- 頻繁使用可選鏈接可能表明數據結構的設計過於複雜。您應該努力實現一個簡單的數據模型。
- 由於某些舊版瀏覽器和JavaScript引擎不支持此功能,您可能需要使用polyfill或轉譯器。
結論
可選鏈接是一個強大的功能,能夠簡化對JavaScript中嵌套對象的屬性和函數的安全訪問。在訪問深度嵌套數據結構時,它特別有效,有助於防止錯誤並提升代碼的可讀性。
您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。