ES13 # 私有字段( Private Fields) 语法:在类中定义真正的私有属性

ES2022引入的私有字段(#)语法为JavaScript类提供了真正的私有属性支持。


私有字段通过#前缀定义,只能在类内部访问,外部无法通过任何方式访问或修改。


相比传统的下划线约定、Symbol或WeakMap方案,私有字段具有更好的封装性、更简洁的语法和更优的性能。


私有字段支持静态字段、方法和getter/setter,但不支持动态添加或子类继承访问。


该特性已被主流浏览器和Node.js支持,TypeScript 3.8+也提供了兼容支持。


私有字段是保护类内部状态的理想选择,使JavaScript的面向对象编程更加完善。


#ES2022 (ES13) 引入的 私有字段(Private Fields) 语法,用于在类中定义真正的私有属性。


1. 基本语法

javascript 复制代码
class MyClass {
  // 私有字段(使用 # 前缀)
  #privateField = 0;
  
  // 私有方法
  #privateMethod() {
    return '私有方法';
  }
  
  // 公共方法可以访问私有字段
  publicMethod() {
    console.log(this.#privateField);
    console.log(this.#privateMethod());
  }
}

const instance = new MyClass();
instance.publicMethod();     // ✅ 正常访问
console.log(instance.#privateField);  // ❌ SyntaxError: 私有字段不能外部访问

2. 为什么需要 # 私有字段?


# 出现之前,JavaScript 没有真正的私有属性,通常用以下方式模拟:

javascript 复制代码
// ❌ 方式1: 下划线约定(只是约定,不是真正的私有)
class User {
  constructor(name) {
    this._name = name;  // 约定为私有,但仍可访问
  }
}
const user = new User('Alice');
console.log(user._name);  // "Alice" - 仍然可以访问

// ❌ 方式2: 闭包(复杂且性能差)
function createUser(name) {
  let _name = name;  // 真正的私有
  return {
    getName() { return _name; },
    setName(value) { _name = value; }
  };
}

// ✅ 方式3: 私有字段(简洁且真正私有)
class User {
  #name;
  constructor(name) {
    this.#name = name;
  }
  getName() { return this.#name; }
}

3. 私有字段的特性

3.1 真正的外部不可访问

javascript 复制代码
class BankAccount {
  #balance = 0;
  
  deposit(amount) {
    this.#balance += amount;
  }
  
  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount();
account.deposit(100);
console.log(account.getBalance());  // 100

// ❌ 以下都会报错
console.log(account.#balance);      // SyntaxError
console.log(account['#balance']);   // undefined(不是真正的属性名)
console.log(Object.keys(account));  // [] - 私有字段不会出现在对象属性中

3.2 硬性私有,无法绕过

javascript 复制代码
class Secret {
  #password = '123456';
  
  getPassword() {
    return this.#password;
  }
}

const secret = new Secret();

// 所有尝试都无法访问私有字段
console.log(secret.#password);           // SyntaxError
console.log(secret['#password']);        // undefined
console.log(Reflect.get(secret, '#password')); // undefined
console.log(Object.getOwnPropertyNames(secret)); // []
console.log(JSON.stringify(secret));     // "{}"

3.3 只能在类内部访问

javascript 复制代码
class Parent {
  #private = 'parent private';
  
  parentMethod() {
    console.log(this.#private);  // ✅ 父类内部可访问
  }
}

class Child extends Parent {
  childMethod() {
    // ❌ 子类不能直接访问父类的私有字段
    console.log(this.#private);  // SyntaxError
  }
}

4. 私有字段 vs 其他方式对比

特性 # 私有字段 _ 约定 Symbol WeakMap
真正私有 ✅ 完全私有 ❌ 仅约定 ⚠️ 可绕过 ✅ 真正私有
语法简洁 ✅ 简洁 ✅ 简洁 ⚠️ 稍复杂 ❌ 复杂
性能 ✅ 优秀 ✅ 优秀 ✅ 优秀 ⚠️ 稍差
调试友好 ✅ DevTools 支持 ✅ 可见 ⚠️ 难调试 ❌ 难调试
继承支持 ⚠️ 子类不能访问 ✅ 可访问 ✅ 可访问 ⚠️ 需手动处理
TypeScript ✅ 支持(3.8+) ✅ 支持 ✅ 支持 ✅ 支持

5. 完整示例对比

javascript 复制代码
// 方式1: 下划线约定
class UserV1 {
  constructor(name, age) {
    this._name = name;     // 约定私有
    this._age = age;
  }
  
  getInfo() {
    return `${this._name}, ${this._age}`;
  }
}

// ❌ 外部仍可访问
const user1 = new UserV1('Alice', 25);
console.log(user1._name);  // "Alice" - 没真正隐藏

// 方式2: Symbol
const _name = Symbol('name');
const _age = Symbol('age');

class UserV2 {
  constructor(name, age) {
    this[_name] = name;
    this[_age] = age;
  }
  
  getInfo() {
    return `${this[_name]}, ${this[_age]}`;
  }
}

// ⚠️ 仍可绕过
const user2 = new UserV2('Alice', 25);
const symbols = Object.getOwnPropertySymbols(user2);
console.log(user2[symbols[0]]);  // "Alice" - 可以访问

// 方式3: WeakMap(真正的私有)
const privateData = new WeakMap();

class UserV3 {
  constructor(name, age) {
    privateData.set(this, { name, age });
  }
  
  getInfo() {
    const data = privateData.get(this);
    return `${data.name}, ${data.age}`;
  }
}

// ✅ 外部无法访问
const user3 = new UserV3('Alice', 25);
console.log(user3.name);  // undefined
console.log(privateData.get(user3));  // 需要 WeakMap 实例,无法访问

// 方式4: 私有字段(最简洁)
class UserV4 {
  #name;
  #age;
  
  constructor(name, age) {
    this.#name = name;
    this.#age = age;
  }
  
  getInfo() {
    return `${this.#name}, ${this.#age}`;
  }
}

// ✅ 完全私有,语法最简洁
const user4 = new UserV4('Alice', 25);
console.log(user4.#name);  // SyntaxError - 无法访问

6. 私有字段的高级用法

6.1 私有方法

javascript 复制代码
class Calculator {
  #result = 0;
  
  // 私有方法
  #validateNumber(num) {
    if (typeof num !== 'number') {
      throw new Error('参数必须是数字');
    }
    return num;
  }
  
  // 私有方法
  #updateResult(value) {
    this.#result = value;
  }
  
  // 公共方法
  add(num) {
    const validNum = this.#validateNumber(num);
    this.#updateResult(this.#result + validNum);
    return this;
  }
  
  getResult() {
    return this.#result;
  }
}

const calc = new Calculator();
calc.add(5).add(3);
console.log(calc.getResult());  // 8
// calc.#validateNumber(10);    // ❌ 无法调用私有方法

6.2 私有静态字段

javascript 复制代码
class Counter {
  // 私有静态字段
  static #count = 0;
  
  constructor() {
    Counter.#count++;
  }
  
  static getCount() {
    return Counter.#count;
  }
  
  // 私有静态方法
  static #reset() {
    Counter.#count = 0;
  }
  
  static resetCount() {
    Counter.#reset();
  }
}

console.log(Counter.getCount());  // 0
new Counter();
new Counter();
console.log(Counter.getCount());  // 2
Counter.resetCount();
console.log(Counter.getCount());  // 0

6.3 私有 getter/setter

javascript 复制代码
class User {
  #firstName;
  #lastName;
  
  constructor(firstName, lastName) {
    this.#firstName = firstName;
    this.#lastName = lastName;
  }
  
  // 私有 getter
  get #fullName() {
    return `${this.#firstName} ${this.#lastName}`;
  }
  
  // 公共方法可以使用私有 getter
  getProfile() {
    return {
      name: this.#fullName,
      initials: `${this.#firstName[0]}.${this.#lastName[0]}.`
    };
  }
}

const user = new User('Alice', 'Lee');
console.log(user.getProfile());
// { name: "Alice Lee", initials: "A.L." }
// user.#fullName  ❌ 无法访问

7. 私有字段的注意事项

7.1 不能动态创建

javascript 复制代码
class MyClass {
  #field = 1;
  
  addField() {
    // ❌ 不能动态创建私有字段
    this.#dynamic = 2;  // SyntaxError
  }
}

7.2 命名唯一性

javascript 复制代码
class MyClass {
  #value = 1;
  
  method() {
    // ✅ 同一个类中可以使用多次
    console.log(this.#value);
    this.#value = 2;
  }
}

// ❌ 不同类之间的同名私有字段不冲突
class OtherClass {
  #value = 100;  // 这是另一个私有字段
}

7.3 序列化行为

javascript 复制代码
class User {
  #password = 'secret';
  name = 'Alice';
  
  toJSON() {
    return {
      name: this.name,
      // 需要手动暴露私有字段
      // #password 不会自动序列化
    };
  }
}

const user = new User();
console.log(JSON.stringify(user));  // {"name":"Alice"}
console.log(Object.keys(user));      // ["name"]

8. 在 Vue 3 中的应用


Composition API 通过模块作用域、闭包或 readonly 实现状态封装

html 复制代码
<script setup>
import { ref, readonly, computed } from 'vue'

// 1. 模块级私有(最彻底)
const API_KEY = 'secret'
function privateHelper() {}

// 2. 组件内私有(仅当前组件可访问)
const internalState = ref(0)
const internalMethod = () => {}

// 3. 公开状态(使用 readonly 保护)
const publicState = ref('visible')
const protectedState = readonly(publicState)

// 4. 通过 defineExpose 控制暴露
defineExpose({
  protectedState,
  publicMethod: () => {}
})
</script>

9. 浏览器兼容性

环境 支持版本
Chrome 74+ (2019年4月)
Firefox 90+ (2021年7月)
Safari 14.1+ (2021年4月)
Edge 79+
Node.js 12+ (需要 --harmony 标志) 14.6+ 原生支持
TypeScript 3.8+

10. 总结

特性 说明
语法 #fieldName 定义私有字段
访问 只能在类内部通过 this.#field 访问
继承 子类不能访问父类私有字段
动态性 不能动态添加私有字段
序列化 私有字段不会出现在 Object.keys()JSON.stringify()
适用场景 需要真正封装的类属性、内部状态保护

一句话总结:

# 私有字段是 JavaScript 原生的私有属性语法,提供了真正的封装性,比传统的下划线约定更安全,比 WeakMap 方案更简洁直观。

相关推荐
WiChP3 小时前
【V0.1B4】从零开始的2D游戏引擎开发之路
前端·javascript·游戏引擎
意法半导体STM323 小时前
【官方原创】STM32CubeProgrammer与STM32 Bootloader连接全流程实战指南 LAT1631
开发语言·前端·javascript·stm32·单片机·嵌入式硬件
Irene19913 小时前
getter 和 方法的区别(数据属性和访问器属性,Vue 3 中,computed 和 getter 的关系和区别)
javascript·vue.js·computed·getter
gCode Teacher 格码致知3 小时前
Javascript提高:Promise、Fetch、Axios、XHR、jQuery AJAX 完整对比-由Deepseek产生
javascript·ajax·jquery
终端鹿3 小时前
Vue3 核心 API 完结篇:toRaw / markRaw / shallowReactive / shallowRef 等进阶响应式 API 详解
前端·javascript·vue.js
sunxunyong3 小时前
集群增加用户&权限
前端·javascript·vue.js
wuhen_n3 小时前
组件测试策略:测试 Props、事件和插槽
前端·javascript·vue.js
zhensherlock3 小时前
Protocol Launcher 系列:Pika 取色器的协议控制(上篇)
前端·javascript·macos·typescript·github·mac·view design
inksci3 小时前
推荐动态群聊二维码制作工具
前端·javascript·微信小程序