es6中实现只读属性推荐使用私有字段+#id配合getter,或object.defineproperty设writable:false,也可用weakmap闭包封装;不推荐仅靠命名约定。

ES6 类本身不支持直接用 readonly 关键字声明只读属性(那是 TypeScript 的语法),JavaScript 原生中需借助语言特性模拟只读行为。核心思路是:**不让外部修改,但允许内部初始化和使用**。
使用私有字段 + getter(推荐,现代写法)
ES2022 引入了私有字段(#name),配合仅提供 getter 的公有访问器,可实现真正运行时的只读保障:
class Person {
#id;
constructor(id, name) {
this.#id = id; // ✅ 内部可赋值
this.name = name;
}
get id() {
return this.#id; // ✅ 只暴露读取
}
// 没有 set id() → 外部无法赋值
}
const p = new Person(123, 'Alice');
console.log(p.id); // 123
p.id = 456; // ❌ 静默失败(非严格模式)或报错(严格模式)
优点:私有字段不可被外部访问或篡改,getter 是唯一出口,语义清晰、安全性高。
使用 Object.defineProperty 配合 writable: false
在构造函数中为实例属性定义不可写的描述符:
- 适用于需要挂载在
this上的公有属性(非私有) - 注意:仅阻止赋值,不阻止删除(除非同时设
configurable: false)
class Product {
constructor(name, price) {
this.name = name;
// 将 price 设为只读属性
Object.defineProperty(this, 'price', {
value: price,
writable: false,
enumerable: true,
configurable: false // 防止被 delete 或重新定义
});
}
}
const item = new Product('Book', 29.9);
console.log(item.price); // 29.9
item.price = 39.9; // ❌ 无效(严格模式下报 TypeError)
delete item.price; // ❌ 失败(因 configurable: false)
使用闭包 + WeakMap(兼容老环境)
适合需支持 ES5/ES6 且要强封装的场景,利用闭包隐藏数据,WeakMap 存储私有值:
const _counter = new WeakMap();
class Counter {
constructor(initial = 0) {
_counter.set(this, { value: initial });
}
get value() {
return _counter.get(this).value;
}
// 不提供 setter → 外部只读
increment() {
_counter.get(this).value++;
}
}
缺点:调试不便、内存管理依赖 WeakMap 特性,现代项目中优先用私有字段。
不推荐的做法:仅靠约定或注释
例如:this._name = 'xxx'; // ? 不要修改! —— 这没有任何技术约束力,纯靠自觉,无法防止误改或恶意操作。
本质上,JavaScript 的“只读”是运行时防护,不是编译时检查。选择哪种方式取决于你的目标环境、是否需要私有性、以及对兼容性的要求。新项目首选私有字段 + getter;需兼容旧引擎再考虑 WeakMap 或 defineProperty。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











