深刻一點 - 爲何說splice 效率低呢

原文: https://zswfx.com/articles/5da713302ddd022595ff506a

咱們在使用 Array.prototype.splice 方法的時候,都會說起說它速度慢,效率低。尤爲在例如 Vue或者React 框架中也不推薦使用,緣由是爲何呢?javascript

splice 方法

方法介紹以下:vue

方法也比較明瞭,就是在數組內刪除或者添加元素。
以下示例:java

// 添加一個元素
const arr = [1, 2, 3]
arr.splice(1, 0, 2, 3)
// [1, 2, 3, 2, 3]
// 刪除元素
arr.splice(2, 2)
// arr: [1, 2, 3]

返回值則是刪除元素的數組,如果添加就是空數組.react

w3c 執行過程

在 w3c 中關於 splice 是如何描述過程的呢?數組

Array.prototype.splice 位於ecmascript 規範中 15.4 數組章節下面的 15.4.4.12 點擊這了便可

下面看關於 splice描述:

框架

下面就用刪除和添加兩個例子來講明規範的操做過程:ecmascript

在規範裏面共有 17步的數據操做:性能

  • 第2步中,splice引入了新組數 A,用來存返回數據結果
  • 第6,7步中,獲得真實開始位置與刪除個數,在這裏進行邊界判斷
  • 第9步這裏判斷當前是不是刪除,若 actualDeleteCount > 0即爲刪除,而後獲得A的刪除數組,這裏就獲取到了要刪除的元素,若刪除元素個數爲0,則跳過A爲空數組,k 爲0, 不然 k爲刪除個數,A 爲刪除元素集合. actualStart 爲傳入的數組中某個下標值, actualDeleteCount 爲傳入某個個數範圍是 0-len
  • 在12步判斷添加元素是否多與刪除個數,若少於刪除個數,數組長度減小。
  • 第13步判斷添加元素多餘刪除元素個數,數組長度增長。見下圖示
  • 第14步初始化開始位置,也就是變量k
  • 第15步中進行元素位置移動,若是添加則會不斷把元素添加到元素內
  • 第16步中計算length,元素長度是由原始長度減去刪除元素加上增長元素的數量。
  • 最後一步就是返回在第9步中獲得移除的元素A.

splice 方法中,咱們會使用狀況以下:es5

  • 刪除元素
  • 添加元素
  • 刪除同時添加元素

刪除元素在第9步處理刪除元素數組,第12步處理元素前移並刪除結尾的元素。添加元素在13步內處理元素後移,並在15步在對應下標下放入元素。刪除元素同時刪除上面每一步都會走到。spa

關於規範一些內部方法說明:
[[HasProperty]](P) 對象上的內部方法,若經過P獲得對象結果爲undefined則爲false,不然爲true。
[[GET]](P) 對象內部方法,經過屬性名P獲取結果。
[[Put]](P, V, Throw) 設置對象屬性P的值爲V,Throw若爲true,遇到錯誤則會拋出TypeError。
[[Delete]](P, Throw) 刪除對象上屬性P,若Throw爲true,遇到錯誤則拋出TypeError.

圖示一個數組刪除數量多於添加數量

操做數組:

[0, 1, 2, 3]

這裏進行 splice(1, 2, 4) 操做,從下標1位置移除2個元素,並添加一個元素

圖示一個數組添加多餘刪除個數

[0, 1, 2, 3]

進行 splice(1, 1, 5, 6) 操做,從下標1的位置刪除一個元素,並插入 5和6的示例。

總結

經過上面規範分析和圖示分析,其實splice之因此」慢「, 是由於每次splice操做除了須要分配新的內存區域去存儲數據外,還須要不斷操做元素的下標,大量移動元素位置,若start=0,豈不是每一個元素都須要移動一次呢?這就是說效率不高緣由。

tips: splice 會修改數組自己,因此在vue和react中數組數據變化不會致使UI變化的緣由之一。

其餘參考:

https://www.jianshu.com/p/483...

更好的插入或者刪除方式

上面說splice 用於三種狀況:

  • 刪除元素
  • 添加元素
  • 刪除同時添加元素

在最新的ecma中有新的方法能夠替代splice用途

刪除數組

使用 filter 代替:

const arr = [1, 2, 3, 4]
// 刪除下標爲2的元素
const newArray = arr.filter((_, index) => index !== 2)
// [1, 2, 4]

添加元素

使用 concat 或者 spread 代替配合 slice 實現任何位置插入:

const array = [1, 2, 3,]
// 下標1 插入10
const newArray = array.slice(0, 1).concat(10, array.slice(1))
// [1, 10, 2, 3]
// const newArray = [...array.slice(0, 1), 10, array.slice(1)]

添加刪除元素

同上

const array = [0, 1, 2, 3, 4, 5]
// 下標位置2位置刪除2個,並插入7,8,9
const newArray = array.slice(0, 2).concat([7, 8, 9], array.slice(4))
// [0, 1, 7, 8, 9, 4, 5]

最後

相信本身,總會有一個辦法解決問題,代碼性能也會一點點提升,歡迎交流。

相關文章
相關標籤/搜索