# vue 2.0双向绑定原理:

1、 Observe递归建立响应式数据,劫持get,当被求值且Dep静态属性target非空时收集依赖(见下面watcher)
2、 Observe劫持set,数据改变时,通知dep,dep分发到所有订阅的观察者(分发见下面Dep)
3、 Dep初始化观察者subs为空,并通过addSub(添加时机见下面watcher)添加观察者,notify(遍历subs,并执行各观察者提供的方法)分发消息到观察者
4、 Watcher初始化时给Dep静态属性target赋值自己(巧妙,只有被Dep静态属性target非空时,Observe get才会收集依赖),并对表达式进行求值,触发get,并被作为依赖收集,收集完毕置空Dep.target,避免依赖重复收集
5、 Compile解析指令,绑定Watcher,每个指令会初始化一个Watcher

总结:

Observe具备了数据监听能力;Compile具备了模板指令解析能力;Watcher作为桥梁链接两者,并通过Dep实现发布订阅,使依赖能被收集,使变化能更新到视图;

// 递归建立响应式
function observe(data) {
    // 这里是简化逻辑
    if (!data || typeof data !== 'object') {
        return;
    }
    Object.keys(data).forEach(function(key) {
        defineReactive(data, key, data[key]);
    });
};

function defineReactive(data, key, val) {
    observe(val); // 递归遍历所有子属性
    var dep = new Dep(); 
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            if (Dep.target) {.  // 判断是否需要添加订阅者
                //只有compile指定了Dep静态属性target时,get才会收集依赖
                dep.addSub(Dep.target); // 在这里添加一个订阅者
            }
            return val;
        },
        set: function(newVal) {
            if (val === newVal) {
                return;
            }
            val = newVal;
            dep.notify(); // 如果数据变化,通知所有订阅者
        }
    });
}
Dep.target = null;

class Dep {
    constructor() {
        this.subs = [];
    }

    addSub(sub) {
        this.subs.push(sub);
    }

    notify() {
        this.subs.forEach(sub => {
            sub.update();
        })
    }
}
Dep.target = null;

class Watcher() {
    constructor(vm, exp, cb) {
        this.cb = cb;
        this.vm = vm;
        this.exp = exp;
        this.value = this.get();  // 将自己添加到订阅器的操作
    }

    update() {
        this.run();
    }

    run() {
        var value = this.vm.data[this.exp];
        var oldVal = this.value;
        if (value !== oldVal) {
            this.value = value;
            this.cb.call(this.vm, value, oldVal);
        }
    }

    get() {
        Dep.target = this;  // 缓存自己
        var value = this.vm.data[this.exp]  // 强制执行监听器里的get函数
        Dep.target = null;  // 释放自己
        return value;
    }
}

function SelfVue (data, el, exp) {
    this.data = data;
    observe(data);
    el.innerHTML = this.data[exp];  // 初始化模板数据的值
    new Watcher(this, exp, function (value) {
        el.innerHTML = value;
    });
    return this;
}