如何为JavaScript对象定义全局Getter/Setter以监听所有属性读写?
当然可以!在JavaScript里,要实现监听对象所有属性(包括后续新增的属性)的读写操作,最现代也最靠谱的方案是用Proxy API——它专门用来创建对象的代理,能拦截并自定义对象的各种基本操作。下面一步步给你实现需求:
简单版:监听所有读写操作
我们可以通过Proxy的get和set陷阱,拦截所有属性的读取和设置行为,触发统一的日志输出:
const obj = { foo: 'bar', boop: "beep" }; // 创建代理对象,替代原对象使用 const proxyObj = new Proxy(obj, { // 拦截属性读取操作 get(target, prop) { console.log("a set/get action was just triggered on obj!"); return target[prop]; // 返回原属性值 }, // 拦截属性设置操作 set(target, prop, value) { console.log("a set/get action was just triggered on obj!"); target[prop] = value; // 给原对象设置新值 return true; // 必须返回true表示设置成功,否则会抛出错误 } }); // 测试效果 proxyObj.foo = "not bar anymore!"; // 输出:a set/get action was just triggered on obj! proxyObj.rand = "a randomly added prop here"; // 输出:a set/get action was just triggered on obj! proxyObj.boop; // 读取属性也会触发日志输出
注意:之后要操作原对象的话,记得使用proxyObj而不是原obj,否则不会触发拦截。
进阶版:输出属性名和对应值
只需要修改Proxy陷阱函数的日志内容,把当前操作的属性名和值打印出来即可:
const obj = { foo: 'bar', boop: "beep" }; const proxyObj = new Proxy(obj, { get(target, prop) { console.log(`a set/get action was just triggered on obj with prop: "${prop}", value: "${target[prop]}".`); return target[prop]; }, set(target, prop, value) { console.log(`a set/get action was just triggered on obj with prop: "${prop}", value: "${value}".`); target[prop] = value; return true; } }); // 测试效果 proxyObj.boop = "burp"; // 输出:a set/get action was just triggered on obj with prop: "boop", value: "burp". proxyObj.newRand = "a new randomly added prop here"; // 输出对应属性名和值的日志 proxyObj.foo; // 读取时会输出当前属性的名称和值
其他可选方案(不推荐用于现代项目)
如果需要兼容非常老旧的环境(不支持ES6),可以考虑以下方案,但它们都有明显局限性:
__defineGetter__/__defineSetter__(已废弃):只能给已有属性添加读写拦截,没法处理后续新增的属性,而且属于非标准API,现在已经被Proxy取代:const obj = { foo: 'bar', boop: "beep" }; // 给已有属性逐个添加拦截 Object.keys(obj).forEach(prop => { let internalValue = obj[prop]; delete obj[prop]; obj.__defineSetter__(prop, (newVal) => { console.log(`a set/get action was just triggered on obj with prop: "${prop}", value: "${newVal}".`); internalValue = newVal; }); obj.__defineGetter__(prop, () => { console.log(`a set/get action was just triggered on obj with prop: "${prop}", value: "${internalValue}".`); return internalValue; }); }); // 新增属性不会被监听 obj.newProp = "test"; // 不会触发任何日志Object.observe(完全废弃):这个API曾经用来监听对象变化,但ES2016已经彻底移除,现在没有浏览器支持它,完全不建议使用。
总结
如果你的项目环境支持ES6+(现在绝大多数浏览器和Node.js版本都支持),优先使用Proxy——它能完美处理所有属性(包括新增属性)的读写拦截,API设计也更优雅灵活。老方案仅适合极端老旧环境的兼容场景,不推荐在现代项目中使用。
内容的提问来源于stack exchange,提问作者aviya.developer
相关产品推荐
相关产品推荐

