美文网首页
最简单的VUE数据劫持的实现

最简单的VUE数据劫持的实现

作者: frank_松 | 来源:发表于2020-03-16 22:55 被阅读0次

    大家做VUE开发的过程中,都会在官网看到一句话:vue会遍历data,通过 Object.defineProperty方法对数据进行劫持,使其转换为响应式。

    看了源码之后,我想自己模仿着写一个简单的例子,去模拟下这种订阅发布模式。以下为代码实现

    // 发布者
    class Dep{
        constructor() {
            this.subs = [];
        }
        addSubs(sub) {
            if (this.subs.indexOf(sub) < 0) {
                this.subs.push(sub);
            }
        }
        notify() {
            this.subs.forEach(item => item.update())
        }
    }
    Dep.target = null;
    
    // 订阅者
    class Watcher {
        constructor(obj, key, updateCb) {
            this.data = obj;
            this.key = key;
            this.updateCb = updateCb;
            this.value = null;
            this.get();
        }
        get() {
            Dep.target = this;
            this.value = this.data[this.key];
            Dep.target = null;
            return this.value;
        }
        update() {
            const oldValue = this.value;
            const newValue = this.get();
            this.updateCb(newValue, oldValue);
        }
    }
    
    // observer类 劫持数据
    
    class Observer {
        constructor(obj) {
            this.data = obj;
            if (this.data == null || typeof this.data !== "object") {
                return;
            }
            if (Array.isArray(this.data)) {
                this.observeArray();
            } else {
                this.walk();
            }
        }
        walk() {
            for (let i in this.data) {
                this.defineReactive(this.data, i);
            }
        }
        observeArray() {
            for (let i = 0; i < this.data.length; i++) {
                observe(this.data[i]);
            }
        }
        defineReactive(obj, key) {
            let val = obj[key];
            observe(val);
            const dep = new Dep();
            Object.defineProperty(obj, key, {
                get() {
                    if (Dep.target) {
                        dep.addSubs(Dep.target)
                    }
                    return val;
                },
                set(newVal) {
                    if (newVal === val) {
                        return;
                    }
                    val = newVal;
                    observe(val);
                    dep.notify();
                }
            })
        }
    }
    // 数据监测方法
    function observe(data) {
        new Observer(data);
    }
    
    // 写一个最简单的例子
    const obj = {
        a: 1
    };
    observe(obj);
    new Watcher(obj, "a", (newVal, oldVal) => {
        console.log("newVal", newVal);
        console.log("oldVal", oldVal + '\n');
    });
    obj.a = 2;
    obj.a = 3;
    
    

    最终控制台输出的结果在我们的意料之中


    image.png

    一个简单的数据劫持功能就做好了。
    当然这里考虑的场景是极为简单的,只支持做简单的效果。比如我写的Watcher类就不能够监听深层级的属性或者数组中某个元素属性的变化。但是用来理解订阅发布模式的思想,应该是比较简单的。

    相关文章

      网友评论

          本文标题:最简单的VUE数据劫持的实现

          本文链接:https://www.haomeiwen.com/subject/tnkaehtx.html