JavaScript内核与高级编程之：`JavaScript`的`Private Fields`：其在`Class`中的实现。

admin
Mon, 25 Aug 2025 08:59:24 +0000
Javascript, fields, javascript, private

各位靓仔靓女们，早上/下午/晚上好！今天咱们聊点刺激的，说说JavaScript里藏得最深的秘密——Private Fields（私有字段）。这玩意儿就像是Class里的秘密日记，只有Class自己能偷看，别人休想知道！ 一、为啥我们需要Private Fields？ 在咱们深入代码之前，先来说说为啥要有这玩意儿。想象一下，你开发了一个超酷的JavaScript Class，给别人用。但是呢，你Class里有些变量，是内部逻辑用的，你压根儿不想让别人瞎改。如果别人一不小心改错了，你的Class就可能崩溃，用户就得骂娘。 以前，我们用一些“约定俗成”的方法来模拟私有变量，比如在变量名前面加个下划线_。 class MyClass { constructor(value) { this._mySecret = value; // 加个下划线表示“别碰我！” } getSecret() { return this._mySecret; } } const instance = new MyClass("Top Secret"); console.log(instance.getSecret( …

继续阅读“JavaScript内核与高级编程之：`JavaScript`的`Private Fields`：其在`Class`中的实现。”

The post JavaScript内核与高级编程之：`JavaScript`的`Private Fields`：其在`Class`中的实现。 first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

各位靓仔靓女们，早上/下午/晚上好！今天咱们聊点刺激的，说说JavaScript里藏得最深的秘密——Private Fields（私有字段）。这玩意儿就像是Class里的秘密日记，只有Class自己能偷看，别人休想知道！

一、为啥我们需要Private Fields？

在咱们深入代码之前，先来说说为啥要有这玩意儿。想象一下，你开发了一个超酷的JavaScript Class，给别人用。但是呢，你Class里有些变量，是内部逻辑用的，你压根儿不想让别人瞎改。如果别人一不小心改错了，你的Class就可能崩溃，用户就得骂娘。

以前，我们用一些“约定俗成”的方法来模拟私有变量，比如在变量名前面加个下划线_。

class MyClass {
  constructor(value) {
    this._mySecret = value; // 加个下划线表示“别碰我！”
  }

  getSecret() {
    return this._mySecret;
  }
}

const instance = new MyClass("Top Secret");
console.log(instance.getSecret()); // "Top Secret"
console.log(instance._mySecret); // "Top Secret"  （照样能访问！）

虽然加了下划线，但这只是个“君子协定”，约束不了坏人。 谁都可以通过instance._mySecret来访问甚至修改这个所谓的“私有”变量。 这显然不安全，不够“私有”。

二、Private Fields闪亮登场！

ES2019 给我们带来了真正的私有字段，使用 # 开头来定义。 只有在Class内部才能访问和修改。

class MyClass {
  #mySecret; // 私有字段声明

  constructor(value) {
    this.#mySecret = value;
  }

  getSecret() {
    return this.#mySecret;
  }
}

const instance = new MyClass("Top Secret");
console.log(instance.getSecret()); // "Top Secret"

// console.log(instance.#mySecret); // 报错！SyntaxError: Private field '#mySecret' must be declared in an enclosing class

看到没？ 如果你试图在Class外部访问#mySecret，浏览器会毫不留情地给你一个SyntaxError。 这才是真正的“闲人免进”！

三、Private Fields的语法规则

必须声明： 私有字段必须在Class的最顶层声明，不能在构造函数或者方法里声明。

使用#开头： 必须使用 # 开头来定义私有字段。

只能在Class内部访问： 只能在Class内部的方法、getter、setter中访问。

每个Class实例都有自己的私有字段： 不同的Class实例，即使是同一个Class创建的，它们的私有字段也是独立的。

四、Private Fields的应用场景

保护内部状态： 防止外部代码意外修改Class的内部状态，保证Class的稳定性。

隐藏实现细节： 将一些复杂的实现细节隐藏起来，只暴露必要的公共接口，简化Class的使用。

保证数据一致性： 通过控制对私有字段的访问，可以保证Class内部数据的一致性。

五、Private Fields vs. Public Fields

特性 | Public Fields (公共字段) | Private Fields (私有字段)
访问权限 | 任何地方都可以访问 | 只能在Class内部访问
声明方式 | this.propertyName = value; | #propertyName;
声明位置 | 构造函数或其他方法中 | Class的最顶层
作用 | 暴露Class的公共属性 | 保护Class的内部状态
可枚举性 | 可枚举 | 不可枚举

六、Private Methods (私有方法)

除了私有字段，我们还可以定义私有方法，同样使用 # 开头。

class MyClass {
  #mySecret;

  constructor(value) {
    this.#mySecret = value;
  }

  getSecret() {
    return this.#processSecret();
  }

  #processSecret() { // 私有方法
    return this.#mySecret.toUpperCase();
  }
}

const instance = new MyClass("Top Secret");
console.log(instance.getSecret()); // "TOP SECRET"

// instance.#processSecret(); // 报错！SyntaxError: Private field '#processSecret' must be declared in an enclosing class

私有方法和私有字段一样，只能在Class内部调用，外部无法访问。

七、Private Getters and Setters (私有Getter和Setter)

你也可以定义私有的getter和setter，用于控制对私有字段的访问。

class MyClass {
  #mySecret;

  constructor(value) {
    this.#mySecret = value;
  }

  get secret() {
    return this.#getSecret();
  }

  set secret(newSecret) {
    this.#setSecret(newSecret);
  }

  #getSecret() {
    return this.#mySecret;
  }

  #setSecret(newSecret) {
    if (typeof newSecret !== 'string') {
      throw new Error('Secret must be a string!');
    }
    this.#mySecret = newSecret;
  }
}

const instance = new MyClass("Original Secret");
console.log(instance.secret); // "Original Secret"

instance.secret = "New Secret";
console.log(instance.secret); // "New Secret"

// instance.#getSecret(); // 报错！

在这个例子中，secret属性的getter和setter，实际上分别调用了私有的#getSecret()和#setSecret()方法。 这样做可以让你在访问和修改私有字段时，添加额外的逻辑，例如数据验证。

八、Static Private Fields and Methods (静态私有字段和方法)

你也可以定义静态的私有字段和方法，它们属于Class本身，而不是Class的实例。

class MyClass {
  static #counter = 0;

  constructor() {
    MyClass.#incrementCounter();
  }

  static getCounter() {
    return MyClass.#counter;
  }

  static #incrementCounter() {
    MyClass.#counter++;
  }
}

const instance1 = new MyClass();
const instance2 = new MyClass();
const instance3 = new MyClass();

console.log(MyClass.getCounter()); // 3
// console.log(MyClass.#counter); // 报错！
// MyClass.#incrementCounter(); // 报错！

静态私有字段和方法，使用 static # 开头定义，只能在Class内部的静态方法中访问。

九、Private Fields的限制

不能在Class外部访问： 这是最主要的限制，也是Private Fields的核心价值。

必须在Class内部声明： 不能在构造函数或其他方法中动态添加私有字段。

不能使用delete删除私有字段： 私有字段一旦声明，就不能被删除。

十、Private Fields的优势

真正的私有性： 区别于以往的“约定俗成”，Private Fields提供了真正的私有性，保证了数据的安全性。

更好的代码可维护性： 通过隐藏内部实现细节，可以降低代码的复杂性，提高代码的可维护性。

更强的代码健壮性： 防止外部代码意外修改Class的内部状态，保证Class的稳定性。

增强代码的可读性： 明确区分公共接口和内部实现，让代码更易于理解。

十一、实际应用案例

假设我们有一个BankAccount Class，用于管理银行账户。我们希望保护账户余额#balance，防止外部代码直接修改。

class BankAccount {
  #balance = 0;

  constructor(initialBalance) {
    if (typeof initialBalance === 'number' && initialBalance >= 0) {
      this.#balance = initialBalance;
    } else {
      throw new Error('Initial balance must be a non-negative number.');
    }
  }

  deposit(amount) {
    if (typeof amount === 'number' && amount > 0) {
      this.#balance += amount;
      return `Deposited ${amount}. New balance: ${this.getBalance()}`;
    } else {
      throw new Error('Deposit amount must be a positive number.');
    }
  }

  withdraw(amount) {
    if (typeof amount === 'number' && amount > 0 && amount <= this.#balance) {
      this.#balance -= amount;
      return `Withdrawn ${amount}. New balance: ${this.getBalance()}`;
    } else {
      throw new Error('Withdrawal amount must be a positive number and less than or equal to the current balance.');
    }
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(1000);
console.log(account.deposit(500));   // "Deposited 500. New balance: 1500"
console.log(account.withdraw(200));  // "Withdrawn 200. New balance: 1300"
console.log(account.getBalance());  // 1300

// account.#balance = 5000; // 报错！不能直接修改

在这个例子中，#balance 是一个私有字段，只能通过 deposit、withdraw 和 getBalance 方法来访问和修改。 这样就保证了账户余额的安全性，防止外部代码随意篡改。

十二、与WeakMap的比较

在Private Fields出现之前，还有一种模拟私有变量的常见方法，就是使用WeakMap。 让我们快速比较一下：

特性 | Private Fields | WeakMap
语法 | #propertyName | WeakMap.set(instance, value)
类型 | 语言特性 | JavaScript对象
性能 | 通常更好 | 稍差
易用性 | 更简单直接 | 稍显繁琐
适用场景 | 大部分场景 | 需要更灵活的控制时

// 使用WeakMap模拟私有变量
const _secret = new WeakMap();

class MyClass {
  constructor(value) {
    _secret.set(this, value);
  }

  getSecret() {
    return _secret.get(this);
  }
}

const instance = new MyClass("Secret with WeakMap");
console.log(instance.getSecret()); // "Secret with WeakMap"

虽然WeakMap也能实现类似的效果，但Private Fields语法更简洁，性能也通常更好。 所以，如果你的目标是真正的私有性，并且可以使用ES2019+，那么Private Fields是更好的选择。

十三、兼容性问题

Private Fields是ES2019的新特性，需要较新的浏览器或Node.js版本才能支持。 如果你的项目需要兼容旧版本的浏览器，可以使用Babel等工具将Private Fields转换为兼容的代码。

十四、总结

Private Fields是JavaScript Class中非常有用的一个特性，它提供了真正的私有性，可以保护Class的内部状态，提高代码的可维护性和健壮性。 虽然有一定的兼容性问题，但随着浏览器和Node.js的不断更新，Private Fields的应用会越来越广泛。

好了，今天的讲座就到这里。 希望大家以后写JavaScript Class的时候，多多使用Private Fields，让你的代码更安全、更可靠！ 散会！