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
- 通过这种方式,你也可以使用可选链访问数组元素。
函数示例:
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
逻辑或运算符将 false、0 和 '' 等值视为假值,而空值合并运算符只有在值为 null 或 undefined 时才使用默认值。
可选链操作符的优势
- 安全地访问嵌套对象:通过使用可选链操作符,不再需要显式地检查存在性,使代码更简洁。
- 避免错误:即使属性为
null或undefined,可选链操作符也能防止运行时错误。 - 提升代码的可读性和可维护性:尤其在处理大量嵌套对象时,代码的可读性显著提高。
使用可选链操作符的注意事项
- 频繁使用可选链操作符可能表明数据结构的设计过于复杂。应该追求简单的数据模型。
- 由于某些旧版浏览器和 JavaScript 引擎不支持可选链操作符,你可能需要使用 polyfill 或转译器。
结论
可选链操作符是一个强大的功能,它简化了在 JavaScript 中安全访问嵌套对象的属性和函数。在访问深层嵌套数据结构时,它特别有效,有助于防止错误并提升代码的可读性。
您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。