當 Vue 處理數組與處理純對象的方式同樣

處理數組方法的弊端

Vue 在響應式的處理中,對數組與對象採用了不一樣的方式,以下源碼所示:javascript

if (Array.isArray(value)) {
  const augment = hasProto
    ? protoAugment
    : copyAugment
  augment(value, arrayMethods, arrayKeys)
  this.observeArray(value)
} else {
  this.walk(value)
}

複製代碼

當值是數組時,Vue 經過攔截數組變異方法的方式來實現響應式,此種方式有兩弊端:html

  • 經過索引設置項,Vue 不能監測到。
  • 修改數組長度時,Vue 也不能監測到。

使用與處理純對象相同的方式

既然在單獨處理數組時,有以上弊端,那爲何不使用和純對象同樣的方式?java

修改部分源碼以下:數組

if (Array.isArray(value)) {
  // const augment = hasProto
  // ? protoAugment
  // : copyAugment
  // augment(value, arrayMethods, arrayKeys)
  // this.observeArray(value)
  this.walk(value)
} else {
  this.walk(value)
}

複製代碼

接着,咱們主要對數組測試兩點,利用索引設置項,以及修改數組長度:app

<div id="app">
  <div>{{ test }}</div>
  <div>{{ test.length }}</div>
  <button @click="someMethod">button</button>
</div>
<script> new Vue({ el: '#app', data: { test: [1, 2, 3, 4] }, methods: { someMethod () { this.test[0] = 5 this.test.length = 10 console.log(this.test) // [5, 2, 3, 4, empty * 6] } } }) </script>
複製代碼

當點擊 button 時,能看到結果: 性能

Wait, 爲何數組裏出現了 null ?測試

null?empty?

當給數組設置 length 時,若是大於數組自己長度,新元素則會以 empty 填充,以下所示:ui

const arr = [1, 2, 3]
arr.length = 5
console.log(arr) // [1, 2, 3, empty * 2]
複製代碼

empty 不一樣於 undefined,在遍歷時,會被忽略:this

const arr = [1, 2, 3]
arr[5] = undefined

console.log(arr) // [1, 2, 3, empty * 2, undefined]

arr.forEach(item => console.log(item))

// 1 2 3 undefined
複製代碼

那麼問題來了,上圖中爲何出現 null?(this.test 打印出來正常,在 html 中渲染出 null)spa

爲了探究此問題,我嘗試在 html 中輸出一個數組變量:

const arr = [1, 2, 3]
document.write(arr)
複製代碼

但是事與願違:

我好像獲得了字符串。

換個對象試試:

const obj = { a: 1 }
document.write(obj)
複製代碼

結果:

輸出的結果,好像被 toString() 了?

const obj = { a: 1 }
console.log(obj.toString()) // [object Object]
複製代碼

也就是說,當你嘗試在頁面輸出一個變量時,JavaScript 會自動調用 toString() 方法。

既然這樣,爲了讓頁面輸出一個變量,須要把變量序列化:

const arr = [1, 2, 3]
arr.length = 6
document.write(JSON.stringify(arr))
複製代碼

獲得結果:

[1, 2, 3, null, null, null]
複製代碼

數組成員裏的 empty 在通過 JSON.stringify 後,轉化成了 null

大數組下的性能問題

從例子中能夠看出,其實 Vue 是可使用與處理純對象的方式來處理數組的。官方解釋不這麼作的緣由是出於對性能的考慮。

爲了獲得驗證,我嘗試使用如下兩種不一樣方式:

  • Vue 單獨處理數組的方式;
  • 和處理純對象相同的方式。

經過二者頁面 Load 時間,來對比性能差別。

測試代碼:

<div id="app">
  <div>{{ test }}</div>
</div>
<script> const arr = new Array(100000) new Vue({ el: '#app', data: { test: arr } }) </script>
複製代碼

當使用 Vue 單獨處理數組的方式時:

當使用與處理純對象相同的方式時:

可見性能上,前者仍是好不少。畢竟遍歷很長的數組,確實是一件很耗性能的事。

個人博客即將同步至騰訊雲+社區,邀請你們一同入駐:cloud.tencent.com/developer/s…

相關文章
相關標籤/搜索