- 數(shù)據(jù)監(jiān)測
- 視圖依賴數(shù)據(jù)收集
- 數(shù)據(jù)變更通知更新視圖
Object.defineProperty的缺陷
Object.defineProperty : 通過設定對象屬性getter/setter方法來監(jiān)聽數(shù)據(jù)的變化复哆,同時getter也用于依賴收集嗅虏,而setter在數(shù)據(jù)變更時通知訂閱者更新視圖谁尸。
function defineReactive(obj, key, value) {
observe(value) // 遞歸子屬性
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
collectDeps() // 收集依賴
return value
},
set(newVal) {
observe(newVal); // 若是對象需要遞歸子屬性
if (newVal !== value) {
notifyRender() // 通知訂閱者更新
value = newVal;
}
}
})
}
function observe(obj) {
if (!obj || typeof obj! === 'object') {
return
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key]);
})
}
var data = {
name: 'wonyun',
sex: 'male'
}
1.無法檢測到對象屬性的新增或刪除
由于js的動態(tài)性命浴,可以為對象追加新的屬性或者刪除其中某個屬性,這點對經(jīng)過Object.defineProperty方法建立的響應式對象來說嫩码,只能追蹤對象已有數(shù)據(jù)是否被修改蛔六,無法追蹤新增屬性和刪除屬性,這就需要另外處理召耘。
Vue.set(obj, propertName/index, value)
2.不能監(jiān)聽數(shù)組的變化
vue在實現(xiàn)數(shù)組的響應式時百炬,它使用了一些hack褐隆,把無法監(jiān)聽數(shù)組的情況通過重寫數(shù)組的部分方法來實現(xiàn)響應式,這也只限制在數(shù)組的push/pop/shift/unshift/splice/sort/reverse七個方法剖踊,其他數(shù)組方法及數(shù)組的使用則無法檢測到庶弃。
Proxy的使用
Proxy,字面意思是代理德澈,是ES6提供的一個新的API歇攻,用于修改某些操作的默認行為,可以理解為在目標對象之前做一層攔截梆造,外部所有的訪問都必須通過這層攔截缴守,通過這層攔截可以做很多事情,比如對數(shù)據(jù)進行過濾镇辉、修改或者收集信息之類屡穗。借用proxy的巧用的一幅圖,它很形象的表達了Proxy的作用忽肛。
ES6原生提供的Proxy構造函數(shù)村砂,用法如下:
var proxy = new Proxy(obj, handler)
其中obj為Proxy要攔截的對象,handler用來定制攔截的操作屹逛,返回一個新的代理對象proxy础废;Proxy代理特點:
1.Proxy的代理針對的是整個對象,而不是像Object.defineProperty針對某個屬性罕模。只需做一層代理就可以監(jiān)聽同級結構下的所有屬性變化评腺,包括新增屬性和刪除屬性
2.Proxy也可以監(jiān)聽數(shù)組的變化
let handler = {
get(target, key){
if (target[key] === 'object' && target[key]!== null) {
// 嵌套子對象也需要進行數(shù)據(jù)代理
return new Proxy(target[key], hanlder)
}
collectDeps() // 收集依賴
return Reflect.get(target, key)
},
set(target, key, value) {
if (key === 'length') return true
notifyRender() // 通知訂閱者更新
return Reflect.set(target, key, value);
}
}
let proxy = new Proxy(data, handler);
proxy.age = 18 // 支持新增屬性
let proxy1 = new Proxy({arr: []}, handler);
proxy1.arr[0] = 'proxy'