vue為什么不能檢測數組的變化


前言

Vue2.0對於響應式數據的實現有一些不足:

  • 無法檢測數組/對象的新增
  • 無法檢測通過索引改變數組的操作。

Vue2.0中響應式數據是通過Object.defineProperty實現,因此無法檢測數組/對象的新增,但為什么無法檢測到通過索引改變數組的操作呢?也是因為Object.defineProperty的原因么?
官方文檔中對於這兩點都是簡要的概括為“由於JavaScript的限制”無法實現,而Object.defineProperty是實現檢測數據改變的方案,那這個限制是指Object.defineProperty嗎?

無法檢測數組的索引變化?

我們來測試一下看看。以下例子,對遍歷數組中的每一項,用Object.defineProperty對其進行監測

function defineReactive(data, key, value) {
	 Object.defineProperty(data, key, {
		 enumerable: true,
		 configurable: true,
		 get: function defineGet() {
			 console.log(`get key: ${key} value: ${value}`)
			 return value
		 },
		 set: function defineSet(newVal) {
			 console.log(`set key: ${key} value: ${newVal}`)
			 value = newVal
		 }
	 })
}
 
function observe(data) {
	Object.keys(data).forEach(function(key) {
		defineReactive(data, key, data[key])
	})
}
 
let arr = [1, 2, 3]
observe(arr)

說明:Vue對數組的7個變異方法(push、pop、shift、unshift、splice、sort、reverse)實現了響應式,因此這里我們就不做測試了。


通過索引改變arr[1],可以發現觸發了set,也就是Object.defineProperty是可以檢測到通過索引改變數組的操作的,那Vue2.0為什么沒有實現呢?
一位開發小哥在github對尤大大提了issue,回答如下:

尤大大回答是因為性能問題。看來不是JavaScript的鍋,更不是Object.defineProperty的鍋了。

驗證

通過我們上面的測試,Object.property是可以檢測到通過索引改變數組的操作的,而Vue沒有實現。那我們看看源碼,Vue的實現邏輯是怎樣的?

我們改下對數組的操作邏輯,遍歷數組對每一項采用Object.defineProperty進行檢測


此時點擊按鈕2,可以發現數值改變為0了,說明通過索引改變arr的操作被檢測到了,Vue是可以實現的!我們進一步確認下:

在defineReactive的Object.defineProperty的set中,加一行console.log,可以發現,當點擊按鈕2時,控制台會輸出“set 0”,更加確切的說明arr[index]=0被set檢測到了。

小結

由於以上提到的問題,Vue3.0采用Proxy替代了Object.defineProperty,Proxy可以完美解決嗎?下篇文章研究研究~

參考:
為什么Vue3.0使用Proxy實現數據監聽(defineProperty表示不背這個鍋)
記一次思否問答的問題思考:Vue為什么不能檢測數組變動


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM