• vue学习笔记之二:object的变化侦测Watcher


    同样的,展示我们可以跑起来的测试代码。当然这是翻看各个类后,按我自己理解整理出来的。原文有export default都取消了,方便一个文件测试。新增一个文件vuetest02.js,将以下代码拷贝

    class Dep {
        constructor() {
            this.subs = [];
        }
        addSub(sub) {
            this.subs.push(sub);
        }
        // removeSub(sub) {
        //     remove(this.subs, sub);
        // }
        depend() {
            if (window.target) {
                this.addSub(window.target)
            }
        }
        notify() {
            const subs = this.subs.slice();
            for (let i = 0; i < subs.length; i++) {
                subs[i].update();
            }
        }
    }
    const bailRE = /[^w.$]/
    
    function parsePath(path){
        if (bailRE.test(path)) {
            return;
        }
        const segments = path.split('.');
        return function (obj) {
            if (!obj) return;
            //console.log(obj);
            for (let i = 0; i < segments.length; i++) {
                //console.log(segments[i]);
                obj = obj[segments[i]];
            }
            return obj;
        }
    }
    
    var window = {};//模拟页面全局属性
    
    class Watcher {
        constructor(vm, expOrFn, cb) {
            this.vm = vm;
            // 执行this.getter(),就可以获取到data.a.b.c的内容
            this.getter = parsePath(expOrFn);
            this.cb = cb;        
            this.value = this.get();
            console.log("this.value..." + this.value);
        }
        get() {
            window.target = this;
            let value = this.getter.call(this.vm, this.vm);
            window.target = undefined;
            return value;
        }
        update() {
            const oldValue = this.value;
            this.value = this.get();
            this.cb.call(this.vm, this.value, oldValue);
        }
    }
    
    class Observer {
        constructor(value) {
            this.value = value;
            if (!Array.isArray(value)) {
                this.walk(value);
            }
        }
        walk(obj) {
            const keys = obj.keys(obj);
            for (let i = 0; i < keys.length; i++) {
                defineReactive(obj, keys[i], obj.keys[i])
            }
        }
    }
    
    function defineReactive(data, key, val) {
        // 新增,递归子属性
        if (typeof val == 'object') {
            new Observer(val);
        }
        let dep = new Dep();
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get: function () {
                dep.depend();
                return val;
            },
            set: function (newVal) {
                if (val === newVal) {
                    return;
                }
                val = newVal;
                dep.notify();            
            }
        })
    }
    
    //与01测试一样的数据准备。
    var base = {};
    defineReactive(base, "name", "kevin");
    
    //准备一个修改DOM的方法。就是说只要属性变化了,就帮我调用这个方法
    function updateVm(vm, newVal, oldValue) {
        console.log(`将控件的外观按新值变化...newVal=${newVal},oldValue=${oldValue}`);
    }
    
    let watch = new Watcher(base, "name", updateVm);
    base.name = "witty";
    base.name = "witty2";
    base.name = "witty3";
    console.log("测试完成。")
    

      在命令窗口运行:node vuetest02.js

    你会发现有两个问题,以下是测试的截图

     第一个问题,updateVm为什么newVal是一个旧值,其实是我并不了解call的方法是什么含义

    Function.call(obj,[param1[,param2[,…[,paramN]]]])
    obj:这个对象将代替Function类里this对象
    params:这个是一个参数列表
    

      原来第一个参数实际上是代表this,于是调用updateVm如下:

    //准备一个修改DOM的方法。就是说只要属性变化了,就帮我调用这个方法
    function updateVm(newVal, oldValue) {
        console.log(`this=${this}`);
        console.log(`将控件的外观按新值变化...newVal=${newVal},oldValue=${oldValue}`);
    }
    

      

    第二个问题,是书本上的代码就有这个问题存在,其实每get一次都会加一次“依赖收集”,解决也很容易,把window.target=this这一句从get方法中删除,改放在构造函数调用get的语句之前就行了。

  • 相关阅读:
    [记录]Eclipse版本选择和安装
    Nexus+Maven安装配置手册
    Eclipse编写Java程序
    Tomcat下载和配置
    SQL Server如何清除连接过的服务器名称历史?
    为文本添加全选Ctrl + A 功能
    配置Eclipse使用TFS源码管理
    [jQuery] jSrcollable
    [ios] cocos2d/cocos2dx 演示
    [c++] 实现类似printf这样的函数
  • 原文地址:https://www.cnblogs.com/kevin-Y/p/12483398.html
Copyright © 2020-2023  润新知