应在原型上定义 getter/setter 以实现共享访问逻辑、节省内存并保持实例纯净;ES5 用 Object.defineProperty,ES6+ 推荐 class 中 get/set 语法,需注意属性遮蔽和 this 指向。

在原型上定义 getter/setter 是实现属性访问控制和动态计算的常用方式,它让实例对象能通过原型链自动继承这些访问器行为,无需在每个实例上重复定义。
为什么要在原型上定义 getter/setter
把 getter/setter 放在原型上,可以让所有实例共享同一套访问逻辑,节省内存;同时保持实例对象自身干净(不污染 this),也便于统一维护。如果写在构造函数内或直接赋给 this,每次新建实例都会创建一份新函数,既冗余又不利于响应式更新或派生计算。
基本写法:使用 Object.defineProperty
ES5 起可通过 Object.defineProperty 在原型对象上添加访问器属性:
function Person(name) {
this._name = name;
}
<p>Object.defineProperty(Person.prototype, 'name', {
get() {
return this._name?.trim();
},
set(value) {
if (typeof value === 'string') {
this._name = value;
} else {
throw new TypeError('Name must be a string');
}
},
// 注意:enumerable 和 configurable 影响 for...in 和 delete 行为
enumerable: true,
configurable: true
});</p>-
必须指定
get或set,不能只写一个而忽略另一个(否则未定义的一方默认为undefined,读/写会静默失败或报错) -
enumerable: false时该属性不会出现在for...in或Object.keys()中(常用于隐藏计算属性) -
configurable: false后无法再修改描述符、删除该属性,也不能重定义为数据属性
ES6+ 更简洁的写法:class + get/set 语法
类声明中直接用 get / set 关键字,本质仍是往原型上定义访问器:
class Rectangle {
constructor(width, height) {
this._width = width;
this._height = height;
}
<p>get area() {
return this._width * this._height;
}</p><p>set area(value) {
const scale = Math.sqrt(value / this.area);
this._width <em>= scale;
this._height </em>= scale;
}
}</p>- 类中的
get area()自动挂载到Rectangle.prototype,所有实例共享 - 注意:不能同时存在同名的数据属性(如
this.area = ...),否则会覆盖原型上的访问器 - 若需在子类中覆写,可用
super.area访问父类原型上的定义
注意事项与常见陷阱
原型链上的访问器看似简单,但容易因执行上下文或属性遮蔽出问题:
- getter/setter 中的
this指向调用时的实际实例,不是原型本身——所以可以安全访问实例私有字段(如this._x) - 若实例自身有同名属性(例如
obj.name = 'Alice'),会屏蔽原型上的访问器,后续读写都走实例属性,不再触发 getter/setter - 用
Object.create(null)创建的对象没有原型,自然也无法继承原型上的访问器 - 在严格模式下,setter 返回值会被忽略;非严格模式下返回值可能被误用,建议不依赖返回值


















