watch js实现
watch 在 JavaScript 中的实现方法
在 JavaScript 中,可以通过多种方式实现类似 watch 的功能,用于监听对象属性的变化。以下是几种常见的实现方法:
使用 Object.defineProperty
Object.defineProperty 是原生 JavaScript 提供的 API,可以用于定义对象的属性及其特性(如可枚举性、可配置性、getter 和 setter 等)。通过定义 setter,可以在属性值变化时触发回调函数。
function watch(obj, prop, callback) {
let value = obj[prop];
Object.defineProperty(obj, prop, {
get() {
return value;
},
set(newValue) {
if (newValue !== value) {
const oldValue = value;
value = newValue;
callback(newValue, oldValue);
}
},
enumerable: true,
configurable: true
});
}
// 示例用法
const obj = { count: 0 };
watch(obj, 'count', (newVal, oldVal) => {
console.log(`count changed from ${oldVal} to ${newVal}`);
});
obj.count = 1; // 输出: count changed from 0 to 1
使用 Proxy
Proxy 是 ES6 引入的功能,可以拦截对象的操作(如属性访问、赋值等)。通过 Proxy,可以更灵活地监听对象的变化。
function watch(obj, callback) {
return new Proxy(obj, {
set(target, prop, value, receiver) {
const oldValue = target[prop];
if (oldValue !== value) {
target[prop] = value;
callback(prop, value, oldValue);
}
return true;
}
});
}
// 示例用法
const obj = { count: 0 };
const watchedObj = watch(obj, (prop, newVal, oldVal) => {
console.log(`${prop} changed from ${oldVal} to ${newVal}`);
});
watchedObj.count = 1; // 输出: count changed from 0 to 1
使用 MutationObserver
MutationObserver 主要用于监听 DOM 树的变化,但也可以用于监听特定元素属性的变化。适用于需要监听 DOM 属性的场景。
const targetNode = document.getElementById('target');
const config = { attributes: true, childList: true, subtree: true };
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes') {
console.log(`Attribute ${mutation.attributeName} changed`);
}
});
});
observer.observe(targetNode, config);
使用第三方库
许多第三方库提供了更强大的 watch 功能,例如 Vue.js 的响应式系统、MobX 等。以下是使用 Vue 的 watch 示例:

const vm = new Vue({
data: { count: 0 },
watch: {
count(newVal, oldVal) {
console.log(`count changed from ${oldVal} to ${newVal}`);
}
}
});
vm.count = 1; // 输出: count changed from 0 to 1
注意事项
- 性能影响:使用
Object.defineProperty或Proxy可能会对性能产生轻微影响,尤其是在频繁修改属性的场景中。 - 兼容性:
Proxy是 ES6 特性,不支持旧版浏览器(如 IE11)。Object.defineProperty的兼容性较好,但无法监听新增属性。 - 深层监听:如果需要监听嵌套对象的属性变化,需要递归地为每个属性设置监听。
以上方法可以根据具体需求选择使用。






