私有属性是面向对象编程中一个重要的概念,它允许我们将某些属性或方法限制在类的内部使用,不允许外部直接访问。这有助于实现封装,提高代码的安全性和可维护性。
function Person() {
// 私有属性
let privateAge = 0;
// 特权方法
this.getAge = function() {
return privateAge;
}
this.setAge = function(age) {
if(age > 0) {
privateAge = age;
}
}
}
const person = new Person();
person.setAge(25);
console.log(person.getAge()); // 25
console.log(person.privateAge); // undefined
const ageSymbol = Symbol('age');
class Person {
constructor() {
this[ageSymbol] = 0;
}
getAge() {
return this[ageSymbol];
}
}
const person = new Person();
console.log(person[ageSymbol]); // 0
// Symbol属性虽然可以访问,但不会在常规的属性枚举中出现
console.log(Object.keys(person)); // []
class Person {
#age = 0; // 私有字段
constructor() {
this.#age = 0;
}
getAge() {
return this.#age;
}
setAge(age) {
if(age > 0) {
this.#age = age;
}
}
}
const person = new Person();
person.setAge(25);
console.log(person.getAge()); // 25
// console.log(person.#age); // SyntaxError
const privateProps = new WeakMap();
class Person {
constructor() {
privateProps.set(this, {
age: 0,
name: ''
});
}
getAge() {
return privateProps.get(this).age;
}
setAge(age) {
if(age > 0) {
privateProps.get(this).age = age;
}
}
}
const person = new Person();
person.setAge(25);
console.log(person.getAge()); // 25
console.log(privateProps.get(person)); // { age: 25, name: '' }
WeakMap 实现的优点:
私有方法与私有属性的实现方式类似,以下展示几种常用方式:
// 使用私有字段语法
class Example {
#privateMethod() {
return 'private method called';
}
publicMethod() {
return this.#privateMethod();
}
}
// 使用 WeakMap 实现
const privateMethods = new WeakMap();
class Example2 {
constructor() {
privateMethods.set(this, {
privateMethod: () => {
return 'private method called';
}
});
}
publicMethod() {
return privateMethods.get(this).privateMethod();
}
}
TypeScript 提供了额外的访问修饰符来控制属性的可访问性:
class Person {
private age: number; // TypeScript 的 private 修饰符
#secretAge: number; // ECMAScript 的私有字段
constructor() {
this.age = 0;
this.#secretAge = 0;
}
// protected 修饰符允许在子类中访问
protected getSecretAge() {
return this.#secretAge;
}
}
class Employee extends Person {
getAge() {
// this.age; // 错误: age 是私有的
return this.getSecretAge(); // 正确: protected 方法可以在子类中访问
}
}
TypeScript 私有属性的特点:
闭包方式
Symbol方式
私有字段语法
如果你的项目需要支持旧版浏览器,可以使用闭包方式
如果你的项目使用现代构建工具且目标浏览器支持,强烈推荐使用私有字段(#)语法:
合理使用私有属性:
class UserAccount {
#balance = 0;
#transactions = [];
deposit(amount) {
if (typeof amount !== 'number' || isNaN(amount)) {
throw new Error('存款金额必须是有效数字');
}
if (amount <= 0) {
throw new Error('存款金额必须大于0');
}
this.#balance += amount;
this.#addTransaction('deposit', amount);
}
withdraw(amount) {
if (typeof amount !== 'number' || isNaN(amount)) {
throw new Error('取款金额必须是有效数字');
}
if (amount <= 0) {
throw new Error('取款金额必须大于0');
}
if (amount > this.#balance) {
throw new Error('余额不足');
}
this.#balance -= amount;
this.#addTransaction('withdraw', amount);
return true;
}
#addTransaction(type, amount) {
this.#transactions.push({
type,
amount,
date: new Date()
});
}
getBalance() {
return this.#balance;
}
getTransactionHistory() {
return [...this.#transactions];
}
}
这个例子展示了私有属性在实际应用中的使用:
私有属性是实现封装的重要机制,JavaScript 提供了多种实现方式。现代JavaScript推荐使用私有字段语法(#),它提供了最好的私有性保证和开发体验。在实际开发中,合理使用私有属性可以提高代码的可维护性和安全性。