Vue2實現響應式的核心:
- 對象:通過defineProperty對對象的已有屬性值的讀取和修改進行劫持(監視/攔截)
- 數組:通過重寫數組更新數組一系列更新元素的方法來實現元素修改的劫持
let data = {
name: 'Liane',
age: 18
}
//模擬組件實例
let _this = {}
//Object.defaineProperty()用法
for(let item in data){
Object.defineProperty(_this,item,{
//每次獲取屬性時都會觸發該屬性的get()方法
get(){
return data[itme]
},
//每次修改屬性值時,都會觸發該屬性的set()方法
set(newValue){
data[item] = newValue
}
})
}
console.log(_this.name) //Liane
_this.name = 'Ann'
console.log(_this.name) //Ann
1、使用observe函數遍歷data的每個屬性
2、調用Object.defineProperty()對每個屬性做響應式處理:利用攔截器屬性get()和set()方法做訂閲-發佈處理。
3、當對一個屬性進行響應式處理的適合,會實例化一個Dep實例,並將用到這個屬性的組件所對應的Watcher實例全部存放在subs數組裏,當屬性被修改時,通知watcher,調用裏面的render函數,進行dom的diff和更新。
問題:
- 需要遍歷需要監聽的每個對象的每個屬性,對其添加definePropert方法,通過其內部的get()和set()方法進行數據的監聽和攔截,實現非常複雜。
- 對象直接新添加的屬性或刪除已有屬性,界面不會自動更新,需要使用Vue.set()
- 直接通過下標替換元素或更新length,界面也不會自動更新
- 數據的響應式處理和視圖未完全解耦
Vue3實現響應式的核心:
通過proxy代理:攔截對data任意屬性的任意操作,包括屬性值的讀寫,屬性的添加,屬性的刪除等。
通過reflect反射,動態對被代理對象的相應屬性進行特定的操作。
//聲明一個普通對象,讓其變成一個proxy代理響應式對象
let user = {
name: 'Liane',
age: 18
}
//通過new運算符,實例化一個proxy對象,new Proxy(target, handler)
//參數1、target--目標對象
//參數2、handler--處理器對象,用來監視數據,及數據操作
let proxyUser = new Proxy(user, {
//獲取目標對象的某個屬性值
get(target, prop) {
console.log('get方法調用了')
//通過Reflect反射,對被代理對象(目標對象)的相應屬性進行特定操作
return Reflect.get(target, prop)
},
//修改目標對象的屬性值/為目標對象添加新的屬性
set(target, prop, value) {
console.log('set方法調用了')
return Reflect.set(target, prop, value)
},
//刪除目標對象上的某個屬性值
deleteProperty(target, prop) {
console.log('delete方法調用了')
return Reflect.deleteProperty(target, prop)
}
})
console.log(proxyUser) //Proxy {name:"Liane",age:18}
//通過代理對象獲取目標對象中的某個屬性值
console.log(proxyUser.name) //Liane
//修改源對象的屬性,代理對象的值也會修改
user.name = 'Ann'
console.log(proxyUser.name) //Ann
//通過代理對象,修改目標對象上的屬性值
proxyUser.name = 'Rose'
console.log(user.name) //Rose
//通過代理對象,刪除目標對象上的屬性值
delete proxyUser.name
console.log(user) //{age:18}
</script >
優點:
- 在我們動態為data添加屬性時,不需要做任何處理,這個屬性就已經是響應式的了。(不用循環遍歷data的每個屬性,對屬性都做一遍響應式處理,而是直接代理整個data對象)
- 數組的任何操作也可以觸發相應。