Getter 和 Setter 是 JavaScript 中拦截属性读写操作的机制,支持数据校验等自定义逻辑;Object.defineProperty 是基础实现方式,getter 无参、setter 单参,需避免 getter 内修改自身引发递归。

Getter 和 Setter 是 JavaScript 中用于拦截对象属性读取和赋值操作的重要机制,它们让开发者能在访问或修改属性时插入自定义逻辑,比如数据校验、格式转换、依赖更新或副作用处理。
用 Object.defineProperty 添加 Getter/Setter
这是最基础的方式,适用于单个对象的属性控制:
- 必须在对象初始化后单独定义,不能直接写在字面量中
- getter 不接受参数,只返回值;setter 接收一个参数(即赋值的值)
- 避免在 getter 中修改自身属性,否则会触发无限递归
示例:限制年龄只能是 0–150 的整数
const person = {};
Object.defineProperty(person, 'age', {
get() {
return this._age;
},
set(value) {
if (Number.isInteger(value) && value >= 0 && value <= 150) {
this._age = value;
} else {
throw new Error('年龄必须是 0 到 150 之间的整数');
}
}
});
在 class 中使用 getter/setter 语法
更简洁自然,适合面向对象场景,也支持继承和重写:
- getter 方法名不带括号,调用时像访问普通属性一样
- setter 必须有且仅有一个形参,代表被赋的值
- 内部通常配合私有字段(如 #name 或 _name)存储真实值
示例:邮箱格式校验 + 自动转小写
class User {
#email;
set email(value) {
if (!/^\S+@\S+\.\S+$/.test(value)) {
throw new Error('邮箱格式不合法');
}
this.#email = value.toLowerCase();
}
get email() {
return this.#email;
}
}
结合 Proxy 实现批量属性控制
当需要对整个对象或动态属性统一拦截时,Proxy 比 defineProperty 更灵活:
- handler.get 和 handler.set 可捕获任意属性的读写,包括未来新增的
- 可集中处理日志、权限、响应式依赖收集等通用逻辑
- 注意不要在 set 中直接给 target 赋值未校验的值,否则绕过验证
示例:为所有数字属性自动四舍五入到两位小数
const data = { price: 19.999, discount: 0.3333 };
const proxied = new Proxy(data, {
set(target, key, value) {
if (typeof value === 'number') {
target[key] = Math.round(value * 100) / 100;
} else {
target[key] = value;
}
return true;
}
});
注意事项与常见陷阱
实际使用中容易忽略的关键点:
- getter/setter 不会出现在 for...in 或 Object.keys() 中(除非 configurable: true 且 enumerable: true)
- JSON.stringify() 默认忽略 getter,需自定义 toJSON 方法才能序列化
- 在 Vue 2 响应式系统中,只有初始化时存在的属性能被 defineProperty 劫持,新增属性需用 $set
- TypeScript 中需明确声明 getter 类型,否则推导可能出错

















