Vue響應原理 definedProperty與proxy實現數據雙向綁定

Vue中從改變一個數據到頁面渲染改變的過程

Vue2 利用definedProperty實現數據綁定

definedProperty 基礎使用:

	var ob={
		a:1,
		b:2
	}
	var _value=ob.a
	Object.defineProperty(ob,'a',{ 
		//writable:true,//可否修改
		//enumerable:false,//是否可被枚舉
		//configurable:false,//是否可被delete
		get(){//獲取時觸發函數
			console.log('取值')
			return _value 
		},
		set(a){//修改時觸發函數,參數爲修改的值
			console.log('存值')
			_value=a
			return _value
		},
	})

實現Vue2 雙向數據綁定

function vue(){
	this.$data={a:1};
	this.el=document.getElementById('add');
	this.virtualdom="";
	this.observe(this.$data);
	this.render;
}
vue.prototype.observe=function(obj){//數據監聽
	var value;
	var self=this;
	for(var key in obj){
		vaule=obj[key];
		if(typeof vaue=='object'){
			this.observe(value)
		}else{
			Object.defineProperty(obj,key,{
				get(){//依賴收集
					return value
				},
				set(newValue){//觸發更新
					value=newValue
					self.render()
				},
			})
		}
	}
}
vue.prototype.render=function(){//數據渲染
	this.virtualdom="I am "+this.$data.a
	this.el.innerHTML=this.virtualdom
}

//數組監聽~思想(未具體實現)
var arrPro=Array.prototype;
var arrayob=Object.create(arrayPro)
var arr=['push','pop','shift'];
arr.forEach((method,index)=>{
	arrayob[methods]=function(){
		var ret=arrayPro[methods].apply(this,arguments);
		dep.notify();//vue源碼中體現 
		return ret;
	}
}) 

let num=0
let vm=new vue()
setInterval(()=>{
	console.log('修改')
	vm.$data.a=num++
},2000)

Vue3 利用proxy實現數據綁定

和defineProperty類似,功能幾乎一樣,用法不同
  • defineProperty是改變原有對象
  • proxy是新建一個代理對象
  • defineProperty只能監聽某一屬性不能設置去全對象監聽;如果需要全對象監聽則需要遞歸修改原對象相關屬性,且defineProperty是對象的方法 數組無法監聽;proxy可以對數組進行監聽

Proxy用於修改某些操作的默認行爲,也可以理解爲在目標對象之前架設一層攔截,外部所有的訪問都必須先通過這層攔截,因此提供了一種機制,可以對外部的訪問進行過濾和修改。這個詞的原理爲代理,在這裏可以表示由它來“代理”某些操作,譯爲“代理器”。
實現Vue3雙向數據綁定

function vue(){
	this.$data={a:1};
	this.el=document.getElementById('add');
	this.virtualdom="";
	this.observe(this.$data);
	this.render;
}
vue.prototype.observe=function(obj){//數據監聽 
	var self=this;
	this.$data=new Proxy(this.$data,{
		get(target,key){
			return target[key]
		},
		set(target,key,newValue){//觸發更新
		 	target[key]=newValue
			self.render()
		},
	}) 
}
vue.prototype.render=function(){//數據渲染
	this.virtualdom="I am "+this.$data.a
	this.el.innerHTML=this.virtualdom
} 

let num=0
let vm=new vue()
setInterval(()=>{
	console.log('修改')
	vm.$data.a=num++
},2000)
	
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章