先溫習下Object.defineProperty數組
var obj = {}; function defineReactive(obj,key,val){ //obj.a讀寫,deps和val閉包儲存。 //defineProperty只能定義一次。 Object.defineProperty(obj,key,{ //觀察者模式 get:function(){ return val; } }); } defineReactive(obj,'a',0); console.log("obj",obj); obj.a = 10; console.log("obj.a",obj.a); // 0,定義無效,貌似只能賦值一次 defineReactive(obj,'a',8); console.log("obj.a",obj.a); //Cannot redefine property: a
代碼:閉包
var obj = {}; var Dep = null; function defineReactive(obj,key,val){ var deps = []; //obj.a讀寫,deps和val閉包儲存。 Object.defineProperty(obj,key,{ //觀察者模式 get:function(){ if(Dep){ //console.log("Dep is:",Dep); deps.push(Dep); } console.log("valx is:",val); return val; }, set: function(newVal){ val = newVal;
//給a賦值的時候,func也執行了,同時b的值也出來了,難點就是兩個函數中的變量都閉包了,deps,value。
//經過deps保存另一個函數的func。同時defineReactive能執行defineComputed的func,這個是不多見的, deps.forEach(func => func()); } }); } //obj.b只讀 function defineComputed(obj,key,func){ func = func.bind(obj); var value; //閉包起來,全局私有變量 Dep = function(){ value = func(); }; value = func(); //執行了 this.a-->get-->打印val = 0; Dep = null; // console.log("Dep isx:",Dep); // 大量閉包,直接給b賦值沒有效果,只能讀取obj.b了。 Object.defineProperty(obj,key,{ get:function(){ return value } }); } defineReactive(obj,'a',0); defineComputed(obj,'b',function(){ var a = this.a; // 這裏只執行一次就執行了deps.push(Dep)。 return a+1; }); console.log(obj.b); // console.log("obj.a=",obj.a); console.log("obj.a=",obj.a); obj.a +=1; //obj.a = obj.a + 1; console.log(obj.b); obj.a +=1; console.log(obj.b); obj.a +=1; console.log(obj.b);
很繞,難點是下面代碼會執行兩次a的get函數。第二次在set函數中的執行value = func(); func函數有this.a中執行了get。並+1賦值給閉包變量value。set函數結束以後。obj.a + 1;而函數
obj.a +=1; //obj.a = obj.a + 1;
下來看看源碼的Dep類(observer/dep.js)ui
模塊代碼結構很清晰、二個全局數組、類的定義和定義一個全局屬性。對外提供兩個接口 pushTarget、popTarget Dep.target = null //
let uid = 0 const targetStack = [] // 全局數組