+
109
-

回答

在 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

网友回复

我知道答案,我要回答