Vue的響應式數據為什么對數組有特殊處理?

vue 中,數組不能像對象一樣被 proxy 或 Object.defineproperty 捕獲的原因在于數組的下標賦值和 Length 屬性修改無法觸發響應式更新機制。1.vue 2 使用 object.defineproperty,vue 3 使用 proxy,但二者都無法追蹤數組下標訪問或長度變更;2.為解決此問題,vue 對數組方法進行劫持,重寫 push、pop、shift、unshift、splice、sort、reverse 等方法以觸發更新;3.開發中應避免使用 arr[index] = newvalue 或 arr.length = newlength 等方式修改數組,而應使用 splice 或重新賦值 map/Filter 等返回新數組的方法。這些限制要求開發者采用特定方式操作數組,以確保視圖同步更新。

Vue的響應式數據為什么對數組有特殊處理?

在 Vue 中,響應式數據對數組的處理確實有些特殊。簡單來說,這是因為 JavaScript 的數組對象本身不具備自動觸發更新的能力,而 Vue 為了實現數組變化時視圖也能同步更新,不得不通過一些“繞道”的方式來實現。

Vue 并不能自動追蹤數組下標的變化或修改數組長度的操作(比如 arr[0] = newValue 或 arr.length = newLength),所以它只能另辟蹊徑,通過重寫數組的一些方法來實現響應式更新。


數組為什么不能像對象一樣被 Proxy/Object.defineProperty 捕獲?

我們知道,Vue 2 使用的是 Object.defineProperty,Vue 3 使用了 Proxy 來監聽對象屬性的變化。但無論是哪種方式,它們都很難直接監聽數組下標訪問或長度變更這種操作。

立即學習前端免費學習筆記(深入)”;

舉個例子:

let arr = [1, 2, 3]; arr[0] = 4;

這段代碼在 JS 中是合法的,但如果你用 Object.defineProperty 或 Proxy 去監聽這個數組,你會發現:

  • 下標賦值不會觸發 set;
  • 修改 .length 屬性也不會觸發更新;
  • 所以 Vue 就無法知道數組變了,自然也就不會更新視圖。

這就導致了一個問題:Vue 無法自動追蹤數組的某些變更方式。


Vue 是如何解決這個問題的?

為了解決這個問題,Vue 對數組做了一些“魔改”:

在 Vue 2 中:

Vue 會把目標數組的原型替換掉,使用一個自定義的“攔截器”原型,其中重寫了如下常用方法:

  • push
  • pop
  • shift
  • unshift
  • splice
  • sort
  • reverse

這些方法都會改變數組內容,所以 Vue 把它們包裝了一下,在調用原始方法的同時通知依賴更新。

在 Vue 3 中:

雖然 Vue 3 使用了更強大的 Proxy,可以更好地追蹤對象屬性的變化,但數組的下標賦值、修改 length 等行為仍然無法自動追蹤。因此 Vue 3 依然沿用了類似 Vue 2 的思路,對這些特定數組方法進行了劫持。

也就是說,即使在 Vue 3 中,你也不能通過下標賦值或者修改 length 來觸發響應式更新


開發中需要注意什么?

如果你在開發過程中遇到了數組變更但視圖沒更新的情況,大概率是因為你用了不被 Vue 攔截的方式去修改數組。常見的幾種情況包括:

  • ? arr[index] = newValue
  • ? arr.length = newLength
  • ? 推薦使用 arr.splice(index, 1, newValue) 替代第一種

還有一些時候我們會用數組的 map/filter/reduce 這些返回新數組的方法,這時候記得要重新賦值:

// 不會觸發更新 this.arr.map(item => item * 2);  // 正確做法 this.arr = this.arr.map(item => item * 2);

因為 map 本身不會改變原數組,只有重新賦值才會觸發 Vue 的響應式機制。


總結一下

Vue 對數組的響應式處理之所以特殊,主要是因為 JS 原生數組的行為限制了自動追蹤能力。Vue 不得不采用“劫持數組方法”的方式來實現更新通知。這要求我們在開發中注意使用合適的方法修改數組,避免踩坑。

基本上就這些。

以上就是Vue的響應式數據<a

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享