在 JavaScript 中有几种方法可以监听变量的变化。我列举几种常用的方法:
使用 Vue 的 watch(如果在 Vue 项目中):
new Vue({ data: { someValue: '' }, watch: { // 基础监听 someValue(newVal, oldVal) { console.log('值变化:', oldVal, '->', newVal); }, // 深度监听对象 someObject: { handler(newVal, oldVal) { console.log('对象变化:', oldVal, '->', newVal); }, deep: true }, // 立即执行 someData: { handler(newVal, oldVal) { console.log('数据变化:', oldVal, '->', newVal); }, immediate: true } } });
使用 Object.defineProperty(Vue2 的实现原理):
let value = ''; let oldValue = value; Object.defineProperty(window, 'watchedValue', { get() { return value; }, set(newValue) { oldValue = value; value = newValue; // 值变化时的回调 onValueChange(value, oldValue); } }); function onValueChange(newValue, oldValue) { console.log('值变化:', oldValue, '->', newValue); } // 使用 watchedValue = 'new value'; // 会触发 onValueChange
使用 Proxy(Vue3 的实现原理):
const data = { value: '' }; const proxy = new Proxy(data, { get(target, property) { return target[property]; }, set(target, property, value) { const oldValue = target[property]; target[property] = value; // 值变化时的回调 onValueChange(property, value, oldValue); return true; } }); function onValueChange(property, newValue, oldValue) { console.log(`${property} 变化:`, oldValue, '->', newValue); } // 使用 proxy.value = 'new value'; // 会触发 onValueChange
使用 MutationObserver(监听 DOM 变化):
// 监听 DOM 元素属性或内容变化 const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { console.log('DOM变化:', mutation); }); }); // 配置观察选项 const config = { attributes: true, // 监听属性变化 childList: true, // 监听子节点变化 characterData: true, // 监听文本内容变化 subtree: true // 监听所有后代节点 }; // 开始观察 const targetNode = document.getElementById('someElement'); observer.observe(targetNode, config); // 停止观察 // observer.disconnect();
创建自定义可观察对象(Observable):
class Observable { constructor(value) { this._value = value; this._listeners = []; } get value() { return this._value; } set value(newValue) { const oldValue = this._value; this._value = newValue; this._notify(newValue, oldValue); } subscribe(listener) { this._listeners.push(listener); // 返回取消订阅函数 return () => { this._listeners = this._listeners.filter(l => l !== listener); }; } _notify(newValue, oldValue) { this._listeners.forEach(listener => listener(newValue, oldValue)); } } // 使用示例 const counter = new Observable(0); // 添加监听器 const unsubscribe = counter.subscribe((newVal, oldVal) => { console.log('计数变化:', oldVal, '->', newVal); }); // 修改值 counter.value = 1; // 会触发监听器 // 取消订阅 unsubscribe();
使用 EventEmitter 模式:
class EventEmitter { constructor() { this._events = {}; } on(event, callback) { if (!this._events[event]) { this._events[event] = []; } this._events[event].push(callback); return () => this.off(event, callback); } off(event, callback) { if (!this._events[event]) return; this._events[event] = this._events[event].filter(cb => cb !== callback); } emit(event, ...args) { if (!this._events[event]) return; this._events[event].forEach(callback => callback(...args)); } } // 使用示例 class WatchableValue extends EventEmitter { constructor(initialValue) { super(); this._value = initialValue; } get value() { return this._value; } set value(newValue) { const oldValue = this._value; this._value = newValue; this.emit('change', newValue, oldValue); } } // 使用 const watchable = new WatchableValue(0); // 添加监听器 const unsubscribe = watchable.on('change', (newVal, oldVal) => { console.log('值变化:', oldVal, '->', newVal); }); // 修改值 watchable.value = 1; // 会触发监听器 // 取消监听 unsubscribe();
选择建议:
在 Vue 项目中,优先使用 watch
需要深度监听对象变化时,使用 Proxy监听
DOM 变化时,使用 MutationObserver
简单场景可以使用 Object.defineProperty
需要更复杂的订阅/发布机制时,可以使用 EventEmitter 模式
需要更灵活的控制时,可以使用自定义 Observable
网友回复
为啥所有的照片分辨率提升工具都会修改照片上的图案细节?
js如何在浏览器中将webm视频的声音分离为单独音频?
微信小程序如何播放第三方域名url的mp4视频?
ai多模态大模型能实时识别视频中的手语为文字吗?
如何远程调试别人的chrome浏览器获取调试信息?
为啥js打开新网页window.open设置窗口宽高无效?
浏览器中js的navigator.mediaDevices.getDisplayMedia屏幕录像无法录制SpeechSynthesisUtterance产生的说话声音?
js中mediaRecorder如何录制window.speechSynthesis声音音频并下载?
python如何直接获取抖音短视频的音频文件url?
js在浏览器中如何使用MediaStream与MediaRecorder实现声音音频多轨道混流?