function Observer(obj, key, value){
    var dep = new Dep();
    if (Object.prototype.toString.call(value) == '[object Object]') {
        Object.keys(value).forEach(function(key){
            new Observer(value,key,value[key])
        })
    };
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function(){
            if (Dep.target) {
                dep.addSub(Dep.target);
            };
            return value;
        },
        set: function(newVal){
            value = newVal;
            dep.notify();
        }
    })
}
 
function Watcher(fn){
    this.update = function(){
        Dep.target = this;
        fn();
        Dep.target = null;
    }
    this.update();
}
function Dep(){
    this.subs = [];
    this.addSub = function (watcher) {
        this.subs.push(watcher);
    }
    this.notify = function(){
        this.subs.forEach(function(watcher){
            watcher.update();
        });
    }
}
  
<div id="test"></div>
 
    var obj = {
        a: 1,
        b: 2,
        c: 3
    }
    Object.keys(obj).forEach(function(key){
        new Observer(obj, key, obj[key])
    });
    new Watcher(function(){
        document.querySelector("#test").innerHTML = obj.a;
    })
 
 
 
 
function Observer(obj, key, value){
        //这里会生成4个dep对象; 分别对应的是属性 a , b, b.b1, c 的派系; 如果一个数据total的计算需要 a的值, 就在第一个dep中添加第三个watcher,
         // 这样obj.a改变, 就会触发第三个watcher的回调, 来更新页面;  obj.c的改变也会触发第三个watcher
            var dep = new Dep();
            if (Object.prototype.toString.call(value) == '[object Object]') {
                Object.keys(value).forEach(function(key){
                    new Observer(value,key,value[key])
                })
            };
            Object.defineProperty(obj, key, {
                enumerable: true,
                configurable: true,
                get: function(){
                    if (Dep.target) {
                        dep.addSub(Dep.target);
                    };
                    return value;
                },
                set: function(newVal){
                    value = newVal;
                    dep.notify();
                }
            })
        }
         
        function Watcher(fn){
            this.update = function(){
                Dep.target = this;
                this.callback();
                Dep.target = null;
            }
            this.callback = fn;
            this.update();
        }
        function Dep(){
            this.subs = [];
            this.addSub = function (watcher) {
                this.subs.push(watcher);
            }
            this.notify = function(){
                this.subs.forEach(function(watcher){
                    watcher.update();
                });
            }
        }
     
         
        var obj = {
            a: 1,
            b: {
                b1: 33
            },
            c: 3
        }
        Object.keys(obj).forEach(function(key){
            new Observer(obj, key, obj[key])
        });
        new Watcher(function(){
            document.querySelector("#app").innerHTML = obj.a; //执行到这里, 有一个取值的操作, 会进入obj对象a属性的get方法
        })
        new Watcher(function(){
            document.querySelector("#test").innerHTML = obj.b.b1; //执行到这里, 也有取值的操作, 先取obj.b, 第一次进入b属性的get方法, 第二次进入b1的get方法
        })
    
     new Watcher(function(){
            document.querySelector("#test").innerHTML = obj.a + obj.c;  
        })
  
     obj.a = 100; //进入ojb属性a的set方法
 
 
function Observer(obj, key, value){
       //这里注册被订阅主体
            var dep = new Dep();
            if (Object.prototype.toString.call(value) == '[object Object]') {
                Object.keys(value).forEach(function(key){
                    new Observer(value,key,value[key])
                })
            };
            Object.defineProperty(obj, key, {
                enumerable: true,
                configurable: true,
                get: function(){
                    if (Dep.target) {
                        dep.addSub(Dep.target);
                    };
                    return value;
                },
                set: function(newVal){
                    value = newVal;
                    dep.notify();
                }
            })
        }
         
        //Watcher, 其实就是订阅者, 这个函数是面向页面更新操作
        function Watcher(fn){
            this.update = function(firstDef){                
                this.callback();                
            }
            this.callback = fn;  //这里其实可以放入多个回调,一个watcher存放多个回调函数, 
            Dep.target = this;
            this.callback(); //先执行一次,来触发obj.a 的get方法; 从而a的dep收集这个watcher,    并且给页面赋值;
            Dep.target = null;
        }
        //这是发布订阅系统, 这个东西是面向对象obj的属性的。 每个属性再defineProperty的时候, 新增了一个dep, 它可以被一个页面多个地方更新依赖,使用;
      
        function Dep(){
            this.subs = [];
            this.addSub = function (watcher) {
                this.subs.push(watcher);
            }
            this.notify = function(){
                this.subs.forEach(function(watcher){
                    watcher.update();
                });
            }
        }
     
         
        var obj = {
            a: 1,
            b: {
                b1: 33
            },
            c: 3
        }
        Object.keys(obj).forEach(function(key){
            new Observer(obj, key, obj[key])
        });
        new Watcher(function(){
            //这里就是收集依赖的过程, obj.a会触发get方法, 这样a属性的dep就添加了这个函数为回调的watcher, 作为依赖一
            document.querySelector("#app").innerHTML = obj.a;
        })
        new Watcher(function(){
            //这里再次收集依赖, obj.a会触发get方法, 这样a属性的dep就 又添加 添加了一个函数watcher, 作为依赖二, 这样
            // a属性的dep就有了两个依赖, 在设置a属性的时候, 就会触发这两个依赖函数.
            document.querySelector("#test").innerHTML = obj.a;
        })
        new Watcher(function(){
            document.querySelector("#test").innerHTML = obj.a + obj.c;
        })
        obj.a = 3;
 
 
function Observer(obj, key, value){
       //这里注册被订阅主体
            var dep = new Dep();
            if (Object.prototype.toString.call(value) == '[object Object]') {
                Object.keys(value).forEach(function(key){
                    new Observer(value,key,value[key])
                })
            };
            Object.defineProperty(obj, key, {
                enumerable: true,
                configurable: true,
                get: function(){
                    if (Dep.target) {
                        dep.addSub(Dep.target);
                    };
                    return value;
                },
                set: function(newVal){
                    value = newVal;
                    dep.notify();
                }
            })
        }
         
        //Watcher, 其实就是订阅者, 这个函数是面向页面更新操作
        function Watcher(fn){
            this.update = function(firstDef){                
                this.callback();                
            }
            this.callback = fn;  //这里其实可以放入多个回调,一个watcher存放多个回调函数, 
            Dep.target = this;
            this.callback(); //先执行一次,来触发obj.a 的get方法; 从而a的dep收集这个watcher,    并且给页面赋值;
            Dep.target = null;
        }
        //这是发布订阅系统, 这个东西是面向对象obj的属性的。 每个属性再defineProperty的时候, 新增了一个dep, 它可以被一个页面多个地方更新依赖,使用;
      
        function Dep(){
            this.subs = [];
            this.addSub = function (watcher) {
                this.subs.push(watcher);
            }
            this.notify = function(){
                this.subs.forEach(function(watcher){
                    watcher.update();
                });
            }
        }
     
         
        var obj = {
            a: 1,
            b: {
                b1: 33
            },
            c: 3
        }
        Object.keys(obj).forEach(function(key){
            new Observer(obj, key, obj[key])
        });
        new Watcher(function(){
            document.querySelector("#app").innerHTML = obj.a;
        })
        new Watcher(function(){
            document.querySelector("#test").innerHTML = obj.b.b1;
        })
        new Watcher(function(){
            document.querySelector("#test").innerHTML = obj.a + obj.c;
        })
        obj.a = 3;
 
 
function Observer(obj, key, value){
            var dep = new Dep();
            if (Object.prototype.toString.call(value) == '[object Object]') {
                Object.keys(value).forEach(function(key){
                    new Observer(value,key,value[key])
                })
            };
            Object.defineProperty(obj, key, {
                enumerable: true,
                configurable: true,
                get: function(){
                    if (Dep.target) {
                        dep.addSub(Dep.target);
                    };
                    return value;
                },
                set: function(newVal){
                    value = newVal;
                    dep.notify();
                }
            })
        }
         
        function Watcher(fn){
            this.update = function(firstDef){
                if(firstDef){
                    Dep.target = this;
                }
                
                this.callback();
                Dep.target = null;
            }
            this.callback = fn;
            this.update(true);
        }
        function Dep(){
            this.subs = [];
            this.addSub = function (watcher) {
                this.subs.push(watcher);
            }
            this.notify = function(){
                this.subs.forEach(function(watcher){
                    watcher.update();
                });
            }
        }
     
         
        var obj = {
            a: 1,
            b: {
                b1: 33
            },
            c: 3
        }
        Object.keys(obj).forEach(function(key){
            new Observer(obj, key, obj[key])
        });
        new Watcher(function(){
            document.querySelector("#app").innerHTML = obj.a;
        })
        new Watcher(function(){
            document.querySelector("#test").innerHTML = obj.b.b1;
        })
        new Watcher(function(){
            document.querySelector("#test").innerHTML = obj.a + obj.c;
        })
        obj.a = 3;