面试题答案
一键面试在JavaScript中,并没有像Java、C# 等语言那样原生的 private
和 protected
访问修饰符。不过,可以通过一些约定和闭包等技术来模拟类似的效果。
模拟私有成员
通常在JavaScript中,我们用下划线 _
作为约定,表示该属性或方法是私有的,不应该在外部直接访问。
// module1.js
const MyClass = (function() {
// 私有变量
let _privateVariable = 'This is a private variable';
function _privateMethod() {
console.log('This is a private method');
}
return class {
constructor() {
// 公共属性
this.publicProperty = 'This is a public property';
}
// 公共方法
publicMethod() {
_privateMethod();
console.log(_privateVariable);
return 'This is a public method';
}
};
})();
export default MyClass;
访问模块中的类及成员
在其他模块中,我们可以导入这个类,并访问其公共成员。
// module2.js
import MyClass from './module1.js';
const myObject = new MyClass();
console.log(myObject.publicProperty);
console.log(myObject.publicMethod());
// 虽然没有严格限制,但不应该直接访问 _privateVariable 和 _privateMethod
// console.log(myObject._privateVariable); // 不推荐这样做
// myObject._privateMethod(); // 不推荐这样做
关于模拟 protected 成员
在ES6 类中,同样没有原生的 protected
修饰符。但可以通过在子类中访问父类的内部状态来模拟 protected
的效果。
// module3.js
const ParentClass = (function() {
let _protectedVariable = 'This is a protected variable';
function _protectedMethod() {
console.log('This is a protected method');
}
return class {
constructor() {
this.publicProperty = 'This is a public property';
}
publicMethod() {
_protectedMethod();
console.log(_protectedVariable);
return 'This is a public method';
}
};
})();
export class ChildClass extends ParentClass {
constructor() {
super();
}
childPublicMethod() {
// 这里可以访问 _protectedVariable 和 _protectedMethod
_protectedMethod();
console.log(_protectedVariable);
return 'This is a method in child class';
}
}
// module4.js
import { ChildClass } from './module3.js';
const childObject = new ChildClass();
console.log(childObject.publicProperty);
console.log(childObject.publicMethod());
console.log(childObject.childPublicMethod());
在实际的TypeScript项目中,可以使用 private
和 protected
关键字,TypeScript 编译器会在编译时进行类型检查,以确保访问控制的正确性。
// module5.ts
class MyClass {
private _privateVariable: string = 'This is a private variable';
protected _protectedVariable: string = 'This is a protected variable';
public publicProperty: string = 'This is a public property';
private _privateMethod() {
console.log('This is a private method');
}
protected _protectedMethod() {
console.log('This is a protected method');
}
public publicMethod() {
this._privateMethod();
console.log(this._privateVariable);
this._protectedMethod();
console.log(this._protectedVariable);
return 'This is a public method';
}
}
export default MyClass;
// module6.ts
import MyClass from './module5.ts';
class ChildClass extends MyClass {
constructor() {
super();
}
childPublicMethod() {
// 可以访问 protected 成员
this._protectedMethod();
console.log(this._protectedVariable);
return 'This is a method in child class';
}
}
const myObject = new MyClass();
console.log(myObject.publicProperty);
console.log(myObject.publicMethod());
// 以下访问会报错,因为是 private 成员
// console.log(myObject._privateVariable);
// myObject._privateMethod();
const childObject = new ChildClass();
console.log(childObject.publicProperty);
console.log(childObject.publicMethod());
console.log(childObject.childPublicMethod());
// 以下访问会报错,因为是 private 成员
// console.log(childObject._privateVariable);
// childObject._privateMethod();