vue3為什麼要用proxy實現雙向資料繫結?
阿新 • • 發佈:2022-05-29
一:object.defineProperty的缺點:
1.因為es5的object.defineProperty無法監聽物件屬性的刪除和新增
2.不能監聽陣列的變化,除了push/pop/shift/unshift/splice/spObject.definert/reverse,其他都不行
3.Object.defineProperty只能遍歷物件屬性直接修改(需要深拷貝進行修改)
二:proxy的優點:
1.直接監聽物件而非屬性
2.直接監聽陣列的變化
3.攔截的方式有很多種(有13種,set,get,has)
4.proxy返回一個新物件,可以操作新物件達到目的
三:proxy的缺點:
proxy有相容性問題,不能用polyfill來相容(polyfill主要撫平不同瀏覽器之間的對js實現的差異)
四:實現vue3雙向繫結
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div></div> <script> const toProxy = new WeakMap(); //存放的是代理後的物件 const toRaw = new WeakMap(); //存放的是代理前的物件 function trigger() { console.log('觸發檢視更新') } function isObject(target) { return typeof target === 'object' && target !== null; } function reactive(target) { if (!isObject(target)) { return target; } let proxy = toProxy.get(target) // 如果代理表中已經存在了 就把這個結果返回 if (proxy) { return proxy } // 如果這個物件已經被代理過了 就直接返回 if (toRaw.has(target)) { return target; } const handlers = { set(target, key, value, receiver) { if (target.hasOwnProperty(key)) { trigger() } return Reflect.set(target, key, value, receiver) }, get(target, key, value, receiver) { const res = Reflect.get(target, key, receiver) if (isObject(target[key])) { return reactive(res) } return res; }, deleteProperty(target, key) { return Reflect.deleteProperty(target, key) } } let observed = new Proxy(target, handlers) toProxy.set(target, observed); toRaw.set(observed, target) return observed } let obj = { name: '溫小鹿', arr: [1, 2, 3] } // let p = reactive(obj) // p.name = 'jw' // let arr = [1, 2 ,3]; // let p = reactive(arr) // p.push(4); // console.log(p) let p = reactive(obj) p = reactive(p) p = reactive(p) p.arr.push(4) console.log(p) </script> </body> </html>