zoukankan      html  css  js  c++  java
  • 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的语句之前就行了。

  • 相关阅读:
    解决Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom:2.12.4
    spring task:annotation-driven 定时任务
    Windows注意目录
    vbScript 备忘
    java 将字符串数组变为字典顺序排序后的字符串数组
    jquery选中以什么开头的元素
    java如何将毫秒数转为相应的年月日格式
    jstl foreach 取index
    jQuery 效果
    js判断一个字符串是以某个字符串开头
  • 原文地址:https://www.cnblogs.com/kevin-Y/p/12483398.html
Copyright © 2011-2022 走看看