来源:https://segmentfault.com/a/1190000004384515
(function(){ //Observer var Observer = cc.Class.extend({ ctor: function(value){ this.value = value; this.walk(value); }, walk: function(value){ Object.keys(value).forEach(function(key, ind, arr){ this.convert(key,value[key]); },this); }, convert: function(key, val){ defineReactive(this.value, key, val); } }); var defineReactive = function(obj, key, val){ var dep = new Dep(); var childOb = observer(val); Object.defineProperty(obj, key, { enumberable: true, configurable: true, get: function(){ console.log("get"); if(Dep.target){ dep.addSub(Dep.target); } return val; }, set: function(newValue){ console.log("set",newValue); var value = val; if(newValue === value){ return; } childOb = observer(newValue); dep.notify(); } }) }; var observer = function(value, vm){ if (!value || typeof value !== 'object') { return; } return new Observer(value); }; //订阅器 var Dep = cc.Class.extend({ ctor: function(){ this.subs = []; }, addSub:function(sub){ this.subs.push(sub); }, notify:function(){ this.subs.forEach(function(sub, ind, arr){ sub.update(); }) }, }); Dep.target = null //watcher var Watcher = cc.Class.extend({ ctor: function(vm, expOrFn, cb){ this.cb = cb; this.vm = vm; //暂时只考虑expression的情况 this.expOrFn = expOrFn; this.value = this.get(); }, update: function(){ this.run(); }, run: function(){ var value = this.get(); if(value !== this.value){ this.value = value ; this.cb.call(this.vm); } }, get: function(){ Dep.target = this; //暂时只考虑expression的情况 var value = this.vm._data[this.expOrFn]; Dep.target = null; return value; } }); //Vue var vue = cc.Class.extend({ ctor: function(options){ this.$options = options || {}; var data = this._data = this.$options.data; Object.keys(data).forEach(function(key, ind, arr){ this._proxy(key); },this); observer(data, this); }, $watcher: function(expOrFn, cb, options){ new Watcher(this, expOrFn, cb); }, _proxy: function(key){ var self = this; Object.defineProperty(self, key, { configurable: true, enumberalbe: true, get:function proxyGetter(){ return self._data[key]; }, set: function proxySetter(val){ self._data[key] = val; } }); } }); mj.vue = vue; })();