在 JavaScript 中,实现面向对象编程中的私有(private)和受保护(protected)成员有几种不同的方式。虽然 JavaScript 本身没有像 Java 或 C++ 那样的原生访问修饰符,但可以通过一些模式和技术来实现类似的功能。
function MyClass() {
// 私有变量 - 只能在构造函数内部访问
var privateVar = 'private';
// 私有方法
function privateMethod() {
return privateVar;
}
// 特权方法 - 可以访问私有成员
this.getPrivate = function() {
return privateMethod();
};
}
var instance = new MyClass();
console.log(instance.getPrivate()); // "private"
console.log(instance.privateVar); // undefined
JavaScript 没有真正的受保护成员,但可以通过约定来实现:
function ParentClass() {
// 约定: 下划线前缀表示受保护
this._protectedVar = 'protected';
}
ParentClass.prototype.getProtected = function() {
return this._protectedVar;
};
function ChildClass() {
ParentClass.call(this);
}
ChildClass.prototype = Object.create(ParentClass.prototype);
var child = new ChildClass();
console.log(child.getProtected()); // "protected"
console.log(child._protectedVar); // "protected" (但可以访问)
class MyClass {
#privateField = 'private'; // 真正的私有字段
// 私有方法 (提案阶段)
#privateMethod() {
return this.#privateField;
}
getPrivate() {
return this.#privateMethod();
}
}
const instance = new MyClass();
console.log(instance.getPrivate()); // "private"
console.log(instance.#privateField); // 报错: SyntaxError
class Parent {
_protectedField = 'protected'; // 约定为受保护
getProtected() {
return this._protectedField;
}
}
class Child extends Parent {
getChildProtected() {
return this._protectedField; // 可以访问父类的"受保护"成员
}
}
const child = new Child();
console.log(child.getProtected()); // "protected"
console.log(child._protectedField); // "protected" (但仍可访问)
const privateProps = new WeakMap();
class MyClass {
constructor() {
privateProps.set(this, {
privateField: 'private',
privateMethod: () => privateProps.get(this).privateField
});
}
getPrivate() {
return privateProps.get(this).privateMethod();
}
}
const instance = new MyClass();
console.log(instance.getPrivate()); // "private"
console.log(instance.privateField); // undefined
TypeScript 提供了更完整的访问控制修饰符:
class MyClass {
private privateField: string = 'private';
protected protectedField: string = 'protected';
private privateMethod(): string {
return this.privateField;
}
public getPrivate(): string {
return this.privateMethod();
}
}
class ChildClass extends MyClass {
public getProtected(): string {
return this.protectedField; // 可以访问受保护成员
// return this.privateField; // 错误: 不能访问私有成员
}
}
#
前缀或 WeakMap 模式_
前缀命名约定现代 JavaScript 开发中,推荐使用 ES2022 的私有字段语法或 TypeScript 的访问修饰符来实现真正的私有和受保护成员。