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
  • 通过这种方式,你也可以使用可选链访问数组元素。

函数示例:

 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

逻辑或运算符将 false0'' 等值视为假值,而空值合并运算符只有在值为 nullundefined 时才使用默认值。

可选链操作符的优势

  • 安全地访问嵌套对象:通过使用可选链操作符,不再需要显式地检查存在性,使代码更简洁。
  • 避免错误:即使属性为 nullundefined,可选链操作符也能防止运行时错误。
  • 提升代码的可读性和可维护性:尤其在处理大量嵌套对象时,代码的可读性显著提高。

使用可选链操作符的注意事项

  • 频繁使用可选链操作符可能表明数据结构的设计过于复杂。应该追求简单的数据模型。
  • 由于某些旧版浏览器和 JavaScript 引擎不支持可选链操作符,你可能需要使用 polyfill 或转译器。

结论

可选链操作符是一个强大的功能,它简化了在 JavaScript 中安全访问嵌套对象的属性和函数。在访问深层嵌套数据结构时,它特别有效,有助于防止错误并提升代码的可读性。

您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。

YouTube Video