vue中的mvvm就是數(shù)據(jù)雙向綁定,也就是數(shù)據(jù)model通過viewmodel影響視圖view,視圖view通過viewmodel影響數(shù)據(jù)model。那么他是具體怎么實(shí)現(xiàn)的呢?其實(shí)就是使用object.defineproperty進(jìn)行數(shù)據(jù)劫持和發(fā)布訂閱模式來實(shí)現(xiàn)。
格式:object.defineproperty(obj,'props',descriptor)
obj:要定義屬性的對(duì)象
props:要定義屬性的名稱
descriptor:要定義和修改的屬性描述
descriptor中常用的描述
configurable:為true時(shí)該屬性的描述符才能夠被改變,同時(shí)該屬性也能從對(duì)應(yīng)的對(duì)象上被刪除。
enumerable:為 true 時(shí),該屬性才會(huì)出現(xiàn)在對(duì)象的枚舉屬性中。就是可以用for循環(huán)輸出屬性
writable:為 true 時(shí),該屬性可以重新定義值
value:該屬性對(duì)應(yīng)的值??梢允侨魏斡行У?JavaScript 值(數(shù)值,對(duì)象,函數(shù)等)。
get:當(dāng)訪問該屬性時(shí),會(huì)調(diào)用此函數(shù)。執(zhí)行時(shí)不傳入任何參數(shù),但是會(huì)傳入 this 對(duì)象(由于繼承關(guān)系,這里的this并不一定是定義該屬性的對(duì)象)。該函數(shù)的返回值會(huì)被用作屬性的值。
set:當(dāng)屬性值被修改時(shí),會(huì)調(diào)用此函數(shù)。該方法接受一個(gè)參數(shù)(也就是被賦予的新值),會(huì)傳入賦值時(shí)的 this 對(duì)象。
var obj={}
Object.defineProperty(obj,'name',{
configurable:true,
get(){ //當(dāng)使用obj.name的時(shí)候回調(diào)用該函數(shù)方法
return ‘1’ //返回一個(gè)值
},set(val){ //當(dāng)使用obj.name=“2” ,則調(diào)用該函數(shù)方法
console.log(val)
}
})
當(dāng)使用set和get時(shí),不能使用value和writable描述
描述符默認(rèn)值匯總
擁有布爾值的鍵 configurable、enumerable 和 writable 的默認(rèn)值都是 false。
屬性值和函數(shù)的鍵 value、get 和 set 字段的默認(rèn)值為 undefined。
var vm = new Sun({
el: '#app',
data: {
a: 1
}
})
function Sun(options = {}) {
this.$options = options; //將實(shí)例中所有的屬性掛載到$options上
var data = this._data = options.data //將用戶傳過來的data賦值到實(shí)例_data上,并賦值給變量data利于循環(huán)
obseve(data) //調(diào)用方法,觀察對(duì)象增加Object.defineproperty來設(shè)置值
for (let key in data) { //遍歷data中對(duì)象,通過object.defineproperty將其賦值到對(duì)象this中
Object.defineProperty(this,key,{
enumerable:true,
get(){
return this._data[key]
},
set(newval){
this._data[key]=newval
}
})
}
}
function Observe(data) {
for (const key in data) { //將data中的屬性賦值出來,對(duì)其進(jìn)行定義object.defineProperty
var val = data[key]
Object.defineProperty(data, key, {
enumerable:true,
get() {
return val
},
set(newval) { //當(dāng)輸入vm._data.a=3 調(diào)用改方法設(shè)置新值
if (newval == val) {
return
}
val = newval; //把新的值賦值給val,以后取值的時(shí)候get就可以讀到新的值
obseve(newval) // //進(jìn)行遞歸,深度的數(shù)據(jù)觀察,賦值為對(duì)象時(shí),也要設(shè)置defineproperty
}
})
}
}
function obseve(data) {
if (typeof data!=='object') return
return new Observe(data)
}
【注】在對(duì)象中 . 是和 [ ] 的意思是一樣的。例 sun.name 等價(jià)于 sun[name] , 但是for...in遍歷下標(biāo)中不能混淆, sun[key] 可不等價(jià)與 sun.key 。在 sun[key] 中 key等于 每一次遍歷的 name,age,sex等。 而sun.key 就相當(dāng)于訪問sun對(duì)象的key屬性