受保护字段的概念
在面向对象编程中,“受保护”(protected)通常是指那些只允许类自身及其子类访问的成员变量或方法。然而,在标准的 JavaScript 中,并没有内置的“受保护”关键字来直接实现这一概念。这与一些传统的面向对象语言如 Java 或 C++ 不同。
尽管如此,我们可以通过一些设计模式和技术手段来模拟“受保护”的行为。主要的方法包括使用闭包、命名约定以及通过构造函数或原型链进行控制。
使用闭包模拟受保护字段
闭包是 JavaScript 中一种非常强大的特性,它允许一个函数访问其外部作用域中的变量,即使该函数在其外部作用域之外执行。我们可以利用这一点来创建类似“受保护”的字段。
示例代码
// www.javascriptcn.com code example
class ProtectedFields {
constructor() {
let _protectedField = '这是受保护的字段';
this.getProtectedField = function () {
return _protectedField;
};
this.setProtectedField = function (value) {
_protectedField = value;
};
}
}
const instance = new ProtectedFields();
console.log(instance.getProtectedField()); // 输出: 这是受保护的字段
instance.setProtectedField('新的值');
console.log(instance.getProtectedField()); // 输出: 新的值
// 尝试直接访问 _protectedField
console.log(instance._protectedField); // undefined在这个例子中,_protectedField 被定义在一个闭包内部,因此它不能被实例直接访问。我们提供了 getProtectedField 和 setProtectedField 方法来间接地访问和修改这个字段。
使用命名约定
另一种常见的做法是使用下划线 _ 前缀来表示“受保护”的字段。虽然这种方法并不提供真正的封装性,但它可以作为一种约定,提醒其他开发者这些字段不应该被直接修改。
示例代码
// www.javascriptcn.com code example
class NamingConvention {
constructor() {
this._protectedField = '这是一个命名约定下的受保护字段';
}
getProtectedField() {
return this._protectedField;
}
setProtectedField(value) {
this._protectedField = value;
}
}
const instance = new NamingConvention();
console.log(instance.getProtectedField()); // 输出: 这是一个命名约定下的受保护字段
instance.setProtectedField('新的值');
console.log(instance.getProtectedField()); // 输出: 新的值
// 尝试直接访问 _protectedField
console.log(instance._protectedField); // 输出: 新的值在这个例子中,_protectedField 被标记为以 _ 开头,这是一种常用的命名约定,暗示该字段应该被视为“受保护”。
使用 ES6 的私有字段
从 ECMAScript 2022 起,JavaScript 引入了私有字段的概念,使用 # 符号作为前缀来声明私有字段。私有字段只能在拥有它们的类内部访问,即使是派生类也不能访问。
示例代码
// www.javascriptcn.com code example
class PrivateFields {
#privateField = '这是私有字段';
getPrivateField() {
return this.#privateField;
}
setPrivateField(value) {
this.#privateField = value;
}
}
const instance = new PrivateFields();
console.log(instance.getPrivateField()); // 输出: 这是私有字段
instance.setPrivateField('新的值');
console.log(instance.getPrivateField()); // 输出: 新的值
// 尝试直接访问 #privateField
console.log(instance.#privateField); // SyntaxError: Private field '#privateField' must be declared in an enclosing class在这个例子中,#privateField 是一个真正的私有字段,只能在 PrivateFields 类内部访问。
总结
虽然 JavaScript 并没有直接支持“受保护”字段的概念,但通过闭包、命名约定以及最新的私有字段特性,我们可以有效地模拟这种行为。选择哪种方法取决于你的具体需求和项目的要求。对于需要高度封装性的场景,推荐使用私有字段;而对于更简单的场景,闭包和命名约定可能就足够了。