Object.defineProperty
vue2.x 以及之前的版本使用 Object.defineProperty 實現數據的雙向綁定,簡單實現下
let obj = {
name: '李四',
address: '上海浦東新區',
flags: {
book: {
page: 153,
name: 'JS'
},
hobby: ['足球', '游戲', '音樂']
}
}
function observer(obj) {
if (typeof obj == 'object') {
for (let key in obj) {
defineReactive(obj, key, obj[key])
}
}
}
function defineReactive(obj, key, value) {
Object.defineProperty(obj, key, {
get() {
console.log('獲取:' + key)
return value
},
set(val) {
observer(val)
console.log(key + "-數據改變了")
value = val
}
})
}
observer(obj)
問題1.刪除或者增加對象屬性無法監聽到
問題2.數組的變化無法監聽到

問題3. 由於是使用遞歸遍歷對象,使用 Object.defineProperty 劫持對象的屬性,如果遍歷的對象層級比較深,花的時間比較久,甚至有性能的問題
proxy
對象用於定義基本操作的自定義行為
簡單來說就是,可以在對目標對象設置一層攔截。無論對目標對象進行什么操作,都要經過這層攔截
let obj = {
name: '李四',
address: '上海浦東新區',
flags: {
book: {
page: 153,
name: 'JS'
},
hobby: ['足球', '游戲', '音樂']
}
}
function observerProxy(obj) {
const handler = {
get(target, key, receiver) {
console.log('獲取:' + key) // 如果是對象,就遞歸添加 proxy 攔截
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], handler)
}
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
console.log('設置:' + key) // 如果是對象,就遞歸添加 proxy 攔截
return Reflect.set(target, key, value, receiver)
}
}
return new Proxy(obj, handler)
}
let newObj = observerProxy(obj)
1.Object.defineProperty 攔截的是對象的屬性,會改變原對象。proxy 是攔截整個對象,通過 new 生成一個新對象,不會改變原對象。
2.proxy 的攔截方式,除了上面的 get 和 set ,還有 11 種。選擇的方式很多 Proxy,也可以監聽一些 Object.defineProperty 監聽不到的操作,比如監聽數組,監聽對象屬性的新增,刪除等。
