吐槽Javascript系列三:數組的陷阱

雖然本系列是吐槽,但並非爲了黑Javascript,而是揭露它的一些特性(怪癖),只有更好的瞭解它,才能更好的使用它。本篇主要介紹數組中常見的隱患點。

龜速的map

在數組中,map是一個功能很強大的方法,先來見識一下:前端

let arr = [5, 2, 0]
  .map(v => {
    return v * 2
  })
  .filter(v => {
    return v > 5
  })

console.log(arr) // [ 10 ]

它能返回一個新的數組,而後進行鏈式調用。別覺得鏈式調用只有ES6中的Promise纔有,es5的數組中早有了!
但據我觀察,有些程序員會把它當成forEach來誤用,以下:程序員

let nums = [1, 3, 5, 7]
nums.map(v => {
  console.log(v)
})

我問:你爲何要這樣用呢?數組遍歷應該用forEach和for循環來進行遍歷,map主要是用來作映射生成新數組。
他答:map也能夠遍歷啊,徹底沒有問題,而且map比forEach還少敲幾個字母,不是更方便嗎?
我答:正常來講,的確能夠這樣用,但遇到大長度數組,涉及到性能的狀況,要用forEach或for,由於他們之間的性能有很大區別,咱們來看一個例子數組

// map 1770ms左右
let sum = 0
let arr = []
for (let i = 0; i < 10 * 1000 * 1000; i++) {
  arr.push(i)
}

console.time('p')
arr.map(v => {
  sum += v
})
console.timeEnd('p')

上面的例子中,若是用map來循環,在個人電腦上大約要2s的時間,而用forEach,470ms左右,用for,則只須要18ms左右。對於前端而言還好,但若是是在Node中(服務端)呢,那但是致命的。
一句話吐槽,map很慢如龜速!函數

刪除的陷阱

數組也是一個對象,能夠用delete運算符來從數組中移除元素,以下:性能

let arr = [1, 3, 5, 7, 9]
delete arr[2]
console.log(arr)

可是這種方式,會致使數組中將留下一個空洞,對於上面的例子來講,數組中的第三項5被刪除,數組長度依舊是5,其餘全部項的索引不變。
有點佔着茅坑不拉shi的感受,經常不是咱們想要的結果。因此刪除經常使用splice方法來作,咱們來看一個例子:es5

// 根據索引curId,刪除list中的項
let curId = 2
let list = [
  {id: 1, name: 'a'},
  {id: 2, name: 'b'},
  {id: 3, name: 'c'},
  {id: 4, name: 'd'}
]

list.forEach((v, index) => {
  if (v.id === curId) {
    list.splice(index, 1)
  }
})

上面代碼將刪除id爲2的對象,刪除後,數組將只有3個元素。看上去沒有什麼問題。但若是數組list中有二個同樣的項(且相鄰)呢?以下:code

let list = [
  {id: 1, name: 'a'},
  {id: 2, name: 'b'},
  {id: 2, name: 'b2'},
  {id: 3, name: 'c'},
  {id: 4, name: 'd'}
]

你會發現,name爲b2的項卻刪除不掉,這是爲何呢?由於forEach遍歷刪除第一項後,此時index爲2,而這時數組也實時改變了,這時的數組的第三項爲{id: 3, name: 'c'},而{id: 2, name: 'b2'}則被跳過了,沒有遍歷到!
這種狀況,要用for循環來作,以下:對象

for (let i = 0; i < list.length; i++) {
  if (list[i].id === curId) {
    list.splice(i, 1)
    i--
  }
}

當刪除一項,得將索引減1,這樣才能正確遍歷每一項。
總結一句話,刪除看狀況,請當心索引!排序

sort的誤用

小明是一個新手前端,他寫了一個以下的升序排序:索引

const arr = [ 0, 1, 5, 10, 15, 10, 100, 99, 100 ]
arr.sort((v1, v2) => {
  return v1 > v2
})
console.log(arr)

跑一跑,徹底沒有問題,看似很正確!但數據再多一點,以下:

const arr = [ 0, 1, 5, 10, 15, 10, -2, -2, 100, 99, 100 ]

就會發現結果已經不對了,排序不能這樣寫!正確的寫法應該是這樣:

arr.sort((v1, v2) => {
  return v1 > v2 ? 1 : -1
})

上面二種寫法看上去很像,但本質卻很不同,而且第一種寫法在某些狀況下返回的結果仍是正確的,這正是隱患所在!
總結一句話:數組排序,比較函數中請返回1/-1而不是true/false!

unshift 命名之傷

每次看到這個方法,都會讓我想起了install和uninstall,STOP!
它還有一個兄弟叫shift,它們兩兄弟一個用於往數組頭部添加項,一個用於往數組頭部刪除項。請看例子:

let colors = new Array()
colors.unshift('black')
console.log(colors) // [ 'black' ]

colors.unshift('red', 'green')
console.log(colors) // [ 'red', 'green', 'black' ]

let item = colors.shift()
console.log(item) // red
console.log(colors) // [ 'green', 'black' ]

一句話吐槽,命名太奇怪!

總結

雖然,上面提到的一些陷阱和槽點值得注意,但平心而論,js中的數組是很是靈活的,其提供的不少方法用起來也很方便。

相關文章
相關標籤/搜索