You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中不使用闭包实现封装?附示例

JavaScript 封装相关问题解答

下划线命名的属性是真私有吗?

下划线开头的属性只是社区约定,完全做不到真正的私有。早期JavaScript没有原生私有语法时,开发者用这个命名方式提醒他人「这是内部状态,不要直接修改」,但实际上外部代码可以随意读写这些属性:

const user = {
  _password: '123456'
};
console.log(user._password); // 直接输出 '123456'
user._password = '654321'; // 直接修改

不用闭包实现封装的可行方案

1. ES6 原生私有字段(推荐)

这是当前引擎原生支持的真正私有方案,无需闭包,语法上用#前缀标记私有字段,外部完全无法访问:

class Wallet {
  // 私有字段,仅类内部可访问
  #balance = 0;

  // 公共接口方法
  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
    }
  }

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

const myWallet = new Wallet();
myWallet.deposit(100);
console.log(myWallet.getBalance()); // 100
console.log(myWallet.#balance); // 抛出语法错误:私有字段不可在类外部访问

2. 结合 Object.freeze 的半私有实现

Object.freeze本身不能实现私有,但可以冻结对象的公共接口,防止外部新增/修改方法。搭配不可枚举属性,能实现类似封装的效果:

用 Symbol 作为内部状态的键

Symbol 的唯一性可以让外部难以直接访问内部状态,结合Object.freeze冻结公共方法:

function createTodoList() {
  const todosSymbol = Symbol('todos');
  const todoList = {
    addTodo(text) {
      this[todosSymbol] = this[todosSymbol] || [];
      this[todosSymbol].push(text);
    },
    getTodos() {
      return [...(this[todosSymbol] || [])]; // 返回副本防止外部修改内部数组
    }
  };
  // 冻结公共接口,禁止新增/修改方法
  return Object.freeze(todoList);
}

const list = createTodoList();
list.addTodo('买牛奶');
console.log(list.getTodos()); // ['买牛奶']
// 外部无法直接拿到内部的todos数组,除非获取对应的Symbol
console.log(Object.getOwnPropertySymbols(list)); // 能拿到Symbol,但属于非常规操作

用 Object.defineProperty 定义不可枚举属性

把内部状态设为不可枚举,这样常规遍历(比如Object.keys)看不到它,再冻结公共接口:

function createCounter() {
  const counter = {
    increment() {
      this._count++;
    },
    getCount() {
      return this._count;
    }
  };
  // 定义内部属性为不可枚举、可写但不可配置
  Object.defineProperty(counter, '_count', {
    value: 0,
    writable: true,
    enumerable: false,
    configurable: false
  });
  // 冻结公共方法,防止篡改
  return Object.freeze(counter);
}

const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1
// 常规遍历拿不到内部属性
console.log(Object.keys(counter)); // ['increment', 'getCount']
// 注意:还是能直接访问_counter,这只是约定性的半私有

内容的提问来源于stack exchange,提问作者Sachin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:09:32