vue2中使用的是object.defineProperty()通過劫持對象的屬性數據的變化進行監聽綁定的,
但對數組的變化監聽不到,所以vue2對數組的原型對象進行了重寫:
// src/core/observer/array.js // 獲取數組的原型Array.prototype,上面有我們常用的數組方法 const arrayProto = Array.prototype // 創建一個空對象arrayMethods,並將arrayMethods的原型指向Array.prototype export const arrayMethods = Object.create(arrayProto) // 列出需要重寫的數組方法名 const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] // 遍歷上述數組方法名,依次將上述重寫后的數組方法添加到arrayMethods對象上 methodsToPatch.forEach(function (method) { // 保存一份當前的方法名對應的數組原始方法 const original = arrayProto[method] // 將重寫后的方法定義到arrayMethods對象上,function mutator() {}就是重寫后的方法 def(arrayMethods, method, function mutator (...args) { // 調用數組原始方法,並傳入參數args,並將執行結果賦給result const result = original.apply(this, args) // 當數組調用重寫后的方法時,this指向該數組,當該數組為響應式時,就可以獲取到其__ob__屬性 const ob = this.__ob__ let inserted switch (method) { case 'push': case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break } if (inserted) ob.observeArray(inserted) // 將當前數組的變更通知給其訂閱者 ob.dep.notify() // 最后返回執行結果result return result }) })
實踐過程中發現:
'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'這些重寫過的方法使用時,vue2中數組數據有進行實時的更新,
但使用下標方式(arr[0] = 'sss')、直接修改數組長度arr.length = 1這兩種方式雖然改變了原數組,但此時VUE檢測不到數組變化,也不會更新視圖;使用watch中的 deep: true 也無效。
解決方法:
this.arr[0] = 'sss' 改寫為 this.$set(this.arr, 0, 'sss')
this.arr.length = 1 改寫為 const temp = this.arr.length - 1;this.arr.splice(1, temp)
vu3 數組中沒有上述問題, 因為使用的是 proxy,數組變化都可以監聽得到。