Object.observe因设计复杂、性能问题及Proxy的出现被废弃,现主要通过Proxy实现对象监听,也可用Object.defineProperty或响应式框架替代。

Object.observe
Proxy
setter/getter
Object.defineProperty
Object.observe
Proxy
要替代
Object.observe
1. 使用 ES6 Proxy
立即学习“Java免费学习笔记(深入)”;
Proxy
get
set
deleteProperty
trap
function createReactiveObject(obj, callback) {
return new Proxy(obj, {
set(target, property, value, receiver) {
const oldValue = target[property];
// 避免不必要的触发,如果新旧值相同(且不是NaN)
if (oldValue === value) {
return true;
}
const result = Reflect.set(target, property, value, receiver);
// 只有成功设置了属性才触发回调
if (result) {
callback({
type: 'update',
property: property,
oldValue: oldValue,
newValue: value,
target: target
});
}
return result;
},
deleteProperty(target, property) {
if (Reflect.has(target, property)) {
const oldValue = target[property];
const result = Reflect.deleteProperty(target, property);
if (result) {
callback({
type: 'delete',
property: property,
oldValue: oldValue,
target: target
});
}
return result;
}
return false; // 属性不存在,删除失败
},
// 也可以拦截属性的添加,但通常 set 已经涵盖了首次赋值
// get(target, property, receiver) { ... }
});
}
let data = { a: 1, b: 'hello' };
let reactiveData = createReactiveObject(data, (change) => {
console.log('对象发生变化:', change);
});
reactiveData.a = 2; // 输出: 对象发生变化: { type: 'update', property: 'a', oldValue: 1, newValue: 2, target: { a: 2, b: 'hello' } }
reactiveData.c = 3; // 输出: 对象发生变化: { type: 'update', property: 'c', oldValue: undefined, newValue: 3, target: { a: 2, b: 'hello', c: 3 } }
delete reactiveData.b; // 输出: 对象发生变化: { type: 'delete', property: 'b', oldValue: 'hello', target: { a: 2, c: 3 } }Proxy
Proxy
2. 使用 Object.defineProperty 定义 Setter/Getter
这是在
Proxy
Object.defineProperty
getter
setter
function defineReactiveProperty(obj, key, val, callback) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
// console.log(`属性 ${key} 被读取`);
return val;
},
set(newVal) {
if (newVal === val) {
return;
}
const oldValue = val;
val = newVal;
callback({
type: 'update',
property: key,
oldValue: oldValue,
newValue: newVal,
target: obj
});
// console.log(`属性 ${key} 被修改为 ${newVal}`);
}
});
}
let oldData = { x: 10, y: 'world' };
defineReactiveProperty(oldData, 'x', oldData.x, (change) => {
console.log('对象属性变化:', change);
});
defineReactiveProperty(oldData, 'y', oldData.y, (change) => {
console.log('对象属性变化:', change);
});
oldData.x = 20; // 输出: 对象属性变化: { type: 'update', property: 'x', oldValue: 10, newValue: 20, target: { x: 20, y: 'world' } }
oldData.y = 'hello world'; // 输出: 对象属性变化: { type: 'update', property: 'y', oldValue: 'world', newValue: 'hello world', target: { x: 20, y: 'hello world' } }
oldData.z = 30; // 无法监听,因为 z 不是通过 defineReactiveProperty 定义的这种方法在 Vue 2.x 中被广泛使用,但它有明显的局限性:无法直接监听对象属性的添加和删除,也无法监听数组索引的变化(需要对数组方法进行额外封装)。
3. 响应式库/框架
如果你正在使用 Vue、React (结合状态管理库如 Redux/MobX)、Angular 等现代前端框架,它们通常已经内置了强大的响应式系统。这些系统在底层会利用
Proxy
Object.defineProperty
reactive
Proxy
Proxy
defineProperty
Object.observe
说实话,
Object.observe
首先,性能与实现复杂度是绕不开的话题。尽管
Object.observe
其次,粒度与实用性的平衡。
Object.observe
add
update
delete
splice
setPrototype
reconfigure
再者,与新兴的 Proxy
Proxy
Object.observe
Proxy
Proxy
Object.observe
Proxy
Object.observe
Proxy
Object.observe
最后,浏览器厂商的采纳意愿也是一个关键因素。虽然 Chrome 率先实现了
Object.observe
Proxy
所以,
Object.observe
Proxy
ES6 的
Proxy
基本原理回顾
Proxy
handler
const handler = {
get(target, property, receiver) {
console.log(`Getting property "${String(property)}"`);
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
console.log(`Setting property "${String(property)}" to "${value}"`);
return Reflect.set(target, property, value, receiver);
}
};
let myObject = { a: 1 };
let proxyObject = new Proxy(myObject, handler);
proxyObject.a; // 输出: Getting property "a"
proxyObject.a = 2; // 输出: Setting property "a" to "2"实现深度监听的挑战与策略
Proxy
proxyObject
set
let nestedData = {
info: { name: 'Alice', age: 30 },
tags: ['js', 'dev']
};
let reactiveNestedData = new Proxy(nestedData, handler);
reactiveNestedData.info.name = 'Bob'; // handler的set不会被触发!
// 因为我们修改的是 info 对象内部的 name 属性,而不是 reactiveNestedData 对象的直接属性要实现深度监听,核心策略是:在 get
Proxy
Proxy
function createDeepReactive(obj, callback) {
const isObject = (val) => val && typeof val === 'object';
return new Proxy(obj, {
get(target, property, receiver) {
const res = Reflect.get(target, property, receiver);
// 如果获取到的值是对象(且不是null),就递归地将其也包装成 Proxy
if (isObject(res)) {
return createDeepReactive(res, callback);
}
return res;
},
set(target, property, value, receiver) {
const oldValue = Reflect.get(target, property, receiver);
// 避免重复设置相同的值
if (oldValue === value) {
return true;
}
// 如果新值是对象,也需要包装成 Proxy
const newValue = isObject(value) ? createDeepReactive(value, callback) : value;
const result = Reflect.set(target, property, newValue, receiver);
if (result) {
callback({
type: 'update',
property: property,
oldValue: oldValue,
newValue: newValue,
target: target
});
}
return result;
},
deleteProperty(target, property) {
if (Reflect.has(target, property)) {
const oldValue = Reflect.get(target, property);
const result = Reflect.deleteProperty(target, property);
if (result) {
callback({
type: 'delete',
property: property,
oldValue: oldValue,
target: target
});
}
return result;
}
return false;
}
});
}
let deepData = {
user: {
name: 'Charlie',
address: {
city: 'New York',
zip: '10001'
}
},
items: [
{ id: 1, name: 'Laptop' },
{ id: 2, name: 'Mouse' }
]
};
let reactiveDeepData = createDeepReactive(deepData, (change) => {
console.log('深度对象变化:', change);
});
reactiveDeepData.user.name = 'David'; // 触发回调
// 输出: 深度对象变化: { type: 'update', property: 'name', oldValue: 'Charlie', newValue: 'David', target: { name: 'David', address: { city: 'New York', zip: '10001' } } }
reactiveDeepData.user.address.city = 'Los Angeles'; // 触发回调
// 输出: 深度对象变化: { type: 'update', property: 'city', oldValue: 'New York', newValue: 'Los Angeles', target: { city: 'Los Angeles', zip: '10001' } }
reactiveDeepData.items.push({ id: 3, name: 'Keyboard' }); // 触发回调 (数组的push本质是修改length属性和添加新索引属性)
// 输出: 深度对象变化: { type: 'update', property: '2', oldValue: undefined, newValue: { id: 3, name: 'Keyboard' }, target: [ { id: 1, name: 'Laptop' }, { id: 2, name: 'Mouse' }, { id: 3, name: 'Keyboard' } ] }
// 输出: 深度对象变化: { type: 'update', property: 'length', oldValue: 2, newValue: 3, target: [ { id: 1, name: 'Laptop' }, { id: 2, name: 'Mouse' }, { id: 3, name: 'Keyboard' } ] }
// 替换整个对象
reactiveDeepData.user = { name: 'Eve', address: { city: 'London', zip: 'SW1A 0AA' } }; // 触发回调
// 输出: 深度对象变化: { type: 'update', property: 'user', oldValue: { name: 'David', address: { city: 'Los Angeles', zip: '10001' } }, newValue: Proxy { ... }, target: { user: Proxy { ... }, items: Proxy { ... } } }最佳实践与注意事项:
get
Proxy
Proxy
Proxy
Reflect
Reflect
Reflect.get
Reflect.set
Reflect.deleteProperty
this
push
pop
splice
length
set
get
apply
Proxy
set
Proxy
reactiveDeepData.user = null
user
Proxy
user
this
Proxy
this
this
this
get
Reflect.apply
bind
this
Proxy
虽然
Proxy
Proxy
1. Object.defineProperty
这个我们前面已经提到了,它
以上就是如何利用JavaScript的Object.observe监听对象变化,以及它被废弃后的替代方案有哪些?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号