利用 proxy 監視物件的變化

jackpan發表於2017-12-21

vue 對於 mvvm 的實現是基於 Object.defineProperty 來實現的, 對於 es6 而言有另外一種類似的監視物件屬性變化的 api, 即使用代理 Proxy

對於這個 api 不熟悉的開發者可以點選這裡

利用 porxy 代理物件的 get, defineProperty, deleteProperty 方法即可實現,程式碼簡潔明瞭

const watch = (object, onChange) => {
   const handler = {
       /*  
           如果 target[property] 為物件時遞迴代理,否則返回屬性值
           @param {object} target
           @param {string} property
           @param {object} [receiver]
       */
       get (target, property, receiver) {
           try {
               return new Proxy(target[property], handler)
           } catch (err) {
               return Reflect.get(target, property, receiver)
           }
       },
       
       /*
           當物件賦值的時候,觸發的代理方法(如果有 set 代理, 則觸發 set 代理,否則觸發該方法)
           @param {object} target
           @param {string} property
           @param {object} descriptor
       */
       defineProperty (target, property, descriptor) {
           onChange() // 賦值時觸發回撥函式
           return Reflect.defineProperty(target, property, descriptor)
       },
       
       /*
           當刪除物件屬性時觸發的代理方法
           @param {object} target
           @param {string} property
       */
       deleteProperty (target, property) {
           onChange() // 刪除屬性時觸發回撥函式
           return Reflect.deleteProperty(target, property)
       }
   }
   
   return new Proxy(object, handler)
}

// demo
let obj = {
   a: 123,
   b: {
       c: 333
   }
}
let i = 0
let watchObj = watch(obj, () => {console.log('Object changed:', ++i)})
watchObj.a = 333
// => 'Object changed: 1'
watchObj.b.c = 444
//=> 'Object changed: 2'
複製程式碼

參考連結

相關文章