vue简版源码之observe.js(二)

Observer.js源码分析

分析源码之前先要知道observer是什么,observer其实就是充当着一个订阅者模式,当对象状态发生改变时会通知观察者,模式适用于根据对象状态进行相应处理的场景。. Observer 并非主动观察,而是被动观察,通常情况下:. 一个Model对应多个View,这里也是使用Observer设计模式最多的地方.

温馨提示:有什么不懂就打印出来看打印结果尝试理解,我自己觉得这样效果还不错
(接下来我会详解这个代码块,你这需要顺着思路理解就好了)
以这个组件模块为例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>MVVM</title>
</head>
<body>
<div id="app">
    <h2>{{name}}</h2>
    <button v-on:click="show" id="btn">提示</button>
</div>
<script src="./mvvm-master/js/observer.js"></script>
<script src="./mvvm-master/js/compile.js"></script>
<script src="./mvvm-master/js/watcher.js"></script>
<script src="./mvvm-master/js/mvvm.js"></script>
<script>
    /**
     * 模版解析: 事件指令解析
     * 1. 从元素节点中取出指令
     * 2. 从指令名中取出事件名
     * 3. 根据指令的值(表达式)从methods中得到对应的回调函数
     * 4. 给当前元素节点绑定指定的事件名和回调函数(指定this指向为vm)
     * 5. 移除元素的指令属性
     */
    const vm = new MVVM({
        el: "#app",
        data: {
            name: "aa"
        },
        methods:{
            show(){
                alert("这是一个提示" + this.name)
            }
        }
    });

    function show(){
        alert("这是一个提示" + this.name)
    }
    show();

    var btn = document.getElementById("btn");
    btn.addEventListener("click", show, false)

</script>
</body>
</html>

observer.js代码如下

function Observer(data) {
    //在Observer实例上暂存data
    //此时的data为Observer原型上的data对象
    console.log(this, data);//打印信息为this:Observer {} data:{name: "aa", age: {…}}
    //所以this.data值就为{name: "aa", age: {…}}
    this.data = data;
     this.walk(data);

打印信息如下:

在这里插入图片描述
Observer原型上有walk,convert,defineReactive三个方法,在Obesever原型中引入convent方法为每个属性增加响应式,通过调用observer原型中的definReactive方法来为每个属性增加响应式,为data中所有层次的属性都创建一个dep实例,

//Observer原型上有walk,convert,defineReactive三个方法
Observer.prototype = {
    walk: function (data) {
        console.log(Observer.prototype);
        var me = this;//指向observer的原型
        //把伪数组转换为数组对里面所有的属性名进行遍历
        Object.keys(data).forEach(function (key) {
            //在Obesever原型中引入convent方法为每个属性增加响应式
            me.convert(key, data[key]);
        });
    },
    convert: function (key, val) {
        //通过调用observer原型中的definReactive方法来为每个属性增加响应式,
        this.defineReactive(this.data, key, val);
    },

    defineReactive: function (data, key, val) {
        //{name: "aa"} "name" "aa"
        console.log(data, key, val);
        //为data中所有层次的属性都创建一个dep实例
        //Dep是data每个对象包括子对象都拥有一个该对象, 当所绑定的数据有变更时, 通过dep.notify()通知Watcher
        var dep = new Dep();
        //递归遍历data中所有层次的属性
        var childObj = observe(val);
        console.log(childObj);
        //为data中所有层次的属性都创建一个dep实例
        Object.defineProperty(data, key, {
            enumerable: true, // 可枚举
            configurable: false, // 不能再define默认配置为false
            get: function () {
                console.log(Dep.target);
                //当Dep.target存在且为null的时候执行dep.depend()
                if (Dep.target) {
                    dep.depend();
                    // Dep {id: 0, subs: Array(1)}
                    console.log(dep);
                }
                return val;
            },
            //监听当前属性值发生改变的时候触发回调函数
            set: function (newVal) {
                if (newVal === val) {
                    return;
                }
                val = newVal;
                // 新的值是object的话,进行监听
                childObj = observe(newVal);
                //通过dep.notify 通知订阅者
                dep.notify();
            }
        });
    }
};

打印信息如下:

在这里插入图片描述

判断value是否存在或者value的数据类型是否为object(递归的终止条件)

function observe(value, vm) {
    //判断value是否存在或者value的数据类型是否为object(递归的终止条件)
    if (!value || typeof value !== 'object') {
        return;
    }

    return new Observer(value);
};

Dep是订阅者watcher对应的数据依赖每个Dep都有唯一的ID,subs用于存放依赖,想subs数组添加依赖移除依赖,设置某个watcher的依赖这里添加了Dep.target是否存在判断,目的是判断是不是watcher的构造函数调用也就是说判断他是watcher的this.get调用的,而不是普通调用

function Dep() {
    //没创建一个dep都会给这个dep增加一个独立的标识
    //每个Dep都有唯一的id
    this.id = uid++;
    //subs用于存放依赖
    this.subs = []; //watcher
}

Dep.prototype = {
    //向subs数组添加依赖
    addSub: function (sub) {
        console.log(sub);

        this.subs.push(sub);
    },
    //设置某个watcher依赖这里添加了Dep.target是否存在判断,目的是判断是不是watcher的
    // 构造函数调用也就是说判断他是watcher的this.get调用的,而不是普通调用
    depend: function () {
        console.log(this);

        if (Dep.target) {
            Dep.target.addDep(this);
        }
    },
    //向subs数组移除依赖
    removeSub: function (sub) {
        var index = this.subs.indexOf(sub);
        if (index != -1) {
            this.subs.splice(index, 1);
        }
    },

    //通知所有绑定的watcher,调用watcher的update()
    notify: function () {
        //遍历subs中所有的watcher的实例
        this.subs.forEach(function (sub) {
            // 每一个watcher的实例调用update方法
            sub.update();
        });
    }
};

Dep.target = null;

打印信息如下:

在这里插入图片描述

写到这里关于Observer.js中的一些知识就结束了,后面会陆续更新vue中的其他源码知识,下期再见!
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值