JS陣列方法總覽及遍歷方法耗時統計

Yokoo發表於2018-10-05

國慶7天假,6天加班,苦澀?。

因為對陣列的處理方法有些還是有點模糊,因此這裡整理彙總一下,方便日後自己查閱。?

01、push(value)將value新增到陣列的最後,返回陣列長度(改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.push(1)
console.log(result)       // 6
console.log(a)            // [1, 2, 3, 4, 5, 1] 原陣列被改變

// More
a = [1, 2, 3, 4, 5]
result = a.push('a', 'b') // 可一次新增多個值
console.log(result)       // 7
console.log(a)            // [1, 2, 3, 4, 5, 'a', 'b']
複製程式碼

02、unshift()新增元素到陣列的開頭,返回陣列的長度(改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.unshift(1)
console.log(result)           // 6
console.log(a)                // [1, 1, 2, 3, 4, 5]

// More
result = a.unshift('a', 'b')  // 可一次新增多個值
console.log(result)           // 8
console.log(a)                // ['a', 'b', 1, 1, 2, 3, 4, 5]
複製程式碼

03、pop()刪除陣列中最後一個元素,返回被刪除元素(改變原陣列)

// Base
let a = [5]
let result = a.pop()
console.log(result)   // 5
console.log(a)        // []

// More
result = a.pop()      // 陣列元素為空後會返回undefined
console.log(result)   // undefined
console.log(a)        // []
複製程式碼

04、shift()刪除陣列第一個元素,返回刪除的元素(改變原陣列)

// Base
let a = [5]
let result = a.shift()
console.log(result)      // 5
console.log(a)           // []

// More
result = a.shift()       // 陣列元素為空後會返回undefined
console.log(result)      // undefined
console.log(a)           // []
複製程式碼

05、join(value)將陣列用value連線為字串(不改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.join(',')
console.log(result)   // '1,2,3,4,5'
console.log(a)        // [1, 2, 3, 4, 5]

// More
let obj = {
  toString() {
    console.log('呼叫了toString()方法!')
    return 'a'
  },
  toValue() {
    console.log('toValue()方法!')
    return 'b'
  }
}
result = a.join(obj) // 使用物件時會呼叫物件自身的toString方法轉化為字串,我們這裡重寫了toString,從而覆蓋了原型鏈上的toString
// 呼叫了toString()方法!
console.log(result)   // 1a2a3a4a5
console.log(a)        // [1, 2, 3, 4, 5]

// join的一個相對的方法是字串的split方法
console.log('1a2a3a4a5'.split('a')) // [1, 2, 3, 4, 5]
複製程式碼

06、reverse()反轉陣列(改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.reverse()
console.log(result)   // [5, 4, 3, 2, 1]
console.log(a)        // [5, 4, 3, 2, 1]

// More
a = [1, [2, 3], [4, 5]]
result = a.reverse()
console.log(result)   // [[4, 5], [2, 3], 1]
console.log(a)        // [[4, 5], [2, 3], 1]
// 可以看到這裡的反轉只是基於陣列的第一層,屬於淺反轉。

// 一個簡單的深反轉,使用遞迴實現
const deepReverse = (array) => {
  let temp = array.reverse()
  temp.forEach(v => {
    if(Object.prototype.toString.call(v) === '[object Array]') {
      deepReverse(v)
    }
  })
  return temp
}
a = [1, [2, 3], [4, 5]]
result = deepReverse(a)
console.log(result)    // [[5, 4], [3, 2], 1]
複製程式碼

07、slice(start, end)返回新陣列,包含原陣列索引start的值到索引end的值,不包含end(不改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.slice(2, 4)
console.log(result)   // [3, 4]
console.log(a)        // [1, 2, 3, 4, 5]

// More
console.log(a.slice(1))         // [2, 3, 4, 5]   只有一個引數且不小於0,則從此索引開始擷取到陣列的末位
console.log(a.slice(-1))        // [5]            只有一個引數且小於0,則從倒數|start|位擷取到陣列的末位
console.log(a.slice(-1, 1))     // []             反向擷取,不合法返回空陣列
console.log(a.slice(1, -1))     // [2, 3, 4]      從第一位擷取到倒數第一位,不包含倒數第一位
console.log(a.slice(-1, -2))    // []             反向擷取,不合法返回空陣列
console.log(a.slice(-2, -1))    // [4]            倒數第二位擷取到倒數第一位
複製程式碼

08、splice(index, count, value)從索引為index處刪除count個元素,插入value(改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.splice(1, 2, 0)
console.log(result)   // [2, 3]
console.log(a)        // [1, 0, 4, 5]

// More
a = [1, 2, 3, 4, 5]
console.log(a.splice(-2))                   // [4. 5]
console.log(a)                              // [1, 2, 3]

a = [1, 2, 3, 4, 5]
console.log(a.splice(-1))                   // [5]
console.log(a)                              // [1, 2, 3, 4]               當引數為單個且小於0時,將從陣列的倒數|index|位擷取到陣列的末位

a = [1, 2, 3, 4, 5]
console.log(a.splice(0))                    // [1, 2, 3, 4, 5]
console.log(a)                              // []

a = [1, 2, 3, 4, 5]
console.log(a.splice(1))                    // [2, 3, 4, 5]
console.log(a)                              // [1]                        當引數為單個且不小於0時,將從當前數代表的索引位開始擷取到陣列的末位

a = [1, 2, 3, 4, 5]
console.log(a.splice(-1, 2))                // [5]
console.log(a)                              // [1, 2, 3, 4]               從倒數第一位開始擷取兩個元素,元素不夠,只返回存在的元素

a = [1, 2, 3, 4, 5]
console.log(a.splice(0, 2, 'a', 'b', 'c'))  // [1, 2]
console.log(a)                              // ["a", "b", "c", 3, 4, 5]   擷取後將value一次填充到陣列被擷取的位置,value的數量大於擷取的數量時,陣列中剩餘的元素後移
複製程式碼

09、sort()對陣列元素進行排序(改變原陣列)

// Base
let a = [31, 22, 27, 1, 9]
let result = a.sort()
console.log(result)   // [1, 22, 27, 31, 9]
console.log(a)        // [1, 22, 27, 31, 9]

// More
a = ['c', 'ac', 'ab', '1c', 13, 12, '13', '12', '3', '2', '1b', '1a', 1, 'aa', 'a', 3, 'b', 2]
a.sort()
console.log(a) // [1, 12, "12", 13, "13", "1a", "1b", "1c", "2", 2, "3", 3, "a", "aa", "ab", "ac", "b", "c"]
                      // 可以看出sort排序是根據位來進行排序,而非值的大小,先比較第一位數字在前,字母在後,若相同則比較後面位(實際是比較各個值轉化為字串後的各個位點的unicode位點)
a = [31, 22, 27, 1, 9]
a.sort((a, b)=>{
  return a - b
})
console.log(a)        // [1, 9, 22, 27, 31]  按數值大小正序排列

a = [31, 22, 27, 1, 9]
a.sort((a, b)=>{
  return b - a
})
console.log(a)        // [31, 27, 22, 9, 1]  按數值大小倒序排列
複製程式碼

10、toString()將陣列中的元素用逗號拼接成字串(不改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.toString()
console.log(result)   // 1,2,3,4,5
console.log(a)        // [1, 2, 3, 4, 5]
複製程式碼

11、indexOf(value)從索引為0開始,檢查陣列是否包含value,有則返回匹配到的第一個索引,沒有返回-1(不改變原陣列)

// Base
let a = [1, 2, 3, 2, 5]
let result = a.indexOf(2)
console.log(result)   // 1
console.log(a)        // [1, 2, 3, 2, 5]

result = a.indexOf(6)
console.log(result)   // -1
console.log(a)        // [1, 2, 3, 2, 5]
複製程式碼

12、lastIndexOf(value)從最後的索引開始,檢查陣列是否包含value,有則返回匹配到的第一個索引,沒有返回-1(不改變原陣列)

// Base
let a = [1, 2, 3, 2, 5]
let result = a.lastIndexOf(2)
console.log(result)   // 3
console.log(a)        // [1, 2, 3, 2, 5]

result = a.lastIndexOf(6)
console.log(result)   // -1
console.log(a)        // [1, 2, 3, 2, 5]
複製程式碼

13、concat(value)將陣列和/或值連線成新陣列(不改變原陣列)

// Base
let a = [1, 2], b = [3, 4], c = 5
let result = a.concat(b, c)
console.log(result)   // [1, 2, 3, 4, 5]
console.log(a)        // [1, 2]

// More
b = [3, [4]]
result = a.concat(b, c)
console.log(result)   // [1, 2, 3, [4], 5] concat對於巢狀陣列無法拉平
console.log(a)        // [1, 2]
複製程式碼

14、fill(value, start, end)使用給定value填充陣列,從索引start開始end結束,不包含end(改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.fill(0, 2, 3)
console.log(result)             // [1, 2, 0, 4, 5]
console.log(a)                  // [1, 2, 0, 4, 5]

// More
a = [1, 2, 3, 4, 5]
console.log(a.fill(1))          // [1, 1, 1, 1, 1]  引數一個時,將該引數覆蓋填充到陣列每一項
a = [1, 2, 3, 4, 5]
console.log(a.fill(1, 2))       // [1, 2, 1, 1, 1]  只有start時,從索引start開始填充到陣列末位
a = [1, 2, 3, 4, 5]
console.log(a.fill(1, -2))      // [1, 2, 3, 1, 1]  只有start且為負數時,從倒數|start|位開始填充到陣列末位
複製程式碼

15、flat()將二維陣列變為一維陣列(不改變原陣列)

// Base
let a = [1, 2, 3, [4, 5]]
let result = a.flat()
console.log(result)   // [1, 2, 3, 4, 5]
console.log(a)        // [1, 2, 3, [4, 5]]

let a = [1, 2, 3, [4, 5, [6, 7, [8, 9]]]]
let result = a.flat()
console.log(result)   // [1, 2, 3, 4, 5, [6, 7, [8, 9]]] 很顯然只能將第二層巢狀陣列“拉平”
console.log(a)        // [1, 2, 3, [4, 5, [6, 7, [8, 9]]]]
複製程式碼

16、flatMap()相當於map與flat的結合(不改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.flatMap((currentValue)=>{
  return [currentValue, currentValue * 2]
})
console.log(result)   // [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]
console.log(a)        // [1, 2, 3, 4, 5]
複製程式碼

17、copyWithin(target, start, end)將陣列從start到end索引的元素(不包含end)複製到target開始的索引位置(改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.copyWithin(0, 3, 5)  
console.log(result)                 // [4, 5, 3, 4, 5]
console.log(a)                      // [4, 5, 3, 4, 5]  索引3到5的元素為4和5,複製到從0開始的位置,替換掉了1和2

// More
a = [1, 2, 3, 4, 5]
console.log(a.copyWithin(2))        // [1, 2, 1, 2, 3]  引數只有一個時,start預設為0,end預設為陣列長度-1
複製程式碼

18、entries()返回一個新的Array迭代器物件,可用for...of遍歷(不改變原陣列)

// Base
let a = [1, 2, 3, 4, 5]
let result = a.entries()
console.log(result.next())   // {value: [0, 1], done: false}    value陣列中第一個元素為索引,第二元素為索引對應的值
...
console.log(result.next())   // {value: [4, 5], done: false}
console.log(result.next())   // {value: undefined, done: true}
console.log(result)          // Array Iterator {}
console.log(a)               // [1, 2, 3, 4, 5]

result = a.entries()
for(let value of result) {
  console.log(value)
}
// [0, 1]
// [1, 2]
// [2, 3]
// [3, 4]
// [4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
result = a.entries()
for(let v of result) { }
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 執行三次,三次的耗時數 518ms 515ms 530ms
複製程式碼

19、keys()返回一個新的Array迭代器物件,可用for...of遍歷(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.keys()
console.log(result.next())   // {value: 0, done: false}  value為索引  
...
console.log(result.next())   // {value: 3, done: false}
console.log(result.next())   // {value: 4, done: false}
console.log(result)          // Array Iterator {}
console.log(a)               // [1, 2, 3, 4, 5]

result = a.keys()
for(let value of result) {
  console.log(value)
}
// 0
// 1
// 2
// 3
// 4

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
result = a.keys()
for(let v of result) { }
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 執行三次,三次的耗時數 223ms 262ms 300ms
複製程式碼

20、values()返回一個新的迭代器(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.values()
console.log(result.next())   // {value: 1, done: false}  value為索引  
...
console.log(result.next())   // {value: 4, done: false}
console.log(result.next())   // {value: 5, done: false}
console.log(result)          // Array Iterator {}
console.log(a)               // [1, 2, 3, 4, 5]

result = a.values()
for(let value of result) {
  console.log(value)
}
// 1
// 2
// 3
// 4
// 5

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
result = a.values()
for(let v of result) { }
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 執行三次,三次的耗時數 254ms 270ms 273ms
複製程式碼

21、forEach()遍歷陣列(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.forEach((v, i)=>{
  console.log(v, i)  
  // 1 0
  // 2 1
  // 3 2
  // 4 3
  // 5 4
})
console.log(result)   // undefined
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.forEach(v=>{})
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 執行三次,三次的耗時數 182ms 188ms 180ms
複製程式碼

22、every(fn)判斷陣列中是否所有元素都滿足fn函式中的條件(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.every((currentValue)=>{
  return currentValue > 0
})
console.log(result)   // true  顯然所有元素都大於0

result = a.every((currentValue)=>{
  return currentValue > 1
})
console.log(result)   // false  1並不大於1
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.every(v=> v > -1 )
let dateEnd = Date.now()
console.log(dateEnd - dateStart) // 執行三次,三次的耗時數 176ms 200ms 186ms

dateStart = Date.now()
a.every(v=> v > 8 )
dateEnd = Date.now()
console.log(dateEnd - dateStart) // 0ms 0ms 0ms 不超過1ms,可見every的判斷是在識別到不滿足的條件時,立刻停止
複製程式碼

23、filter(fn)返回陣列中滿足fn函式中條件的集合(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.filter((currentValue)=>{
  return currentValue > 4
})
console.log(result)   // [5] 只有5滿足條件
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.filter(v=> v > -1 )
let dateEnd = Date.now()
console.log(dateEnd - dateStart) // 執行三次,三次的耗時數 584ms 660ms 552ms 全部值都滿足條件的情況

a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.filter(v=> v < 0 )
let dateEnd = Date.now()
console.log(dateEnd - dateStart) // 200ms 194ms 183ms 這個時候才個forEach接近,這也是與forEach本身只有遍歷的功能,沒有執行其他邏輯相關
複製程式碼

24、find(fn)返回陣列中第一個匹配fn函式中條件的值沒有則返回undefined(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.find((currentValue)=>{
  return currentValue > 3
})
console.log(result)   // 4
console.log(a)        // [1, 2, 3, 4, 5]

let result = a.find((currentValue)=>{
  return currentValue > 5
})
console.log(result)   // undefined
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.find(v=> v < 0 )
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 185ms 197ms 203ms 全部不滿足的情況下,效率與forEach相當

a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.find(v=> v > 10 )
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 0ms 0ms 0ms 小於1ms,可以判斷當匹配到滿足條件的第一個值後,立刻停止迴圈,與every相當
複製程式碼

25、findIndex(fn)返回陣列中第一個匹配fn函式中條件的索引沒有則返回undefined(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.findIndex((currentValue)=>{
  return currentValue > 3
})
console.log(result)   // 3
console.log(a)        // [1, 2, 3, 4, 5]

let result = a.findIndex((currentValue)=>{
  return currentValue > 5
})
console.log(result)   // -1
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.findIndex(v=> v < 0 )
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 185ms 183ms 187ms 與find相當

a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.findIndex(v=> v > 10 )
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 0ms 0ms 0ms 與find相當
複製程式碼

26、includes()返回一個布林值,表示某個陣列是否包含給定的值(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.includes(2)
console.log(result)   // true
console.log(a)        // [1, 2, 3, 4, 5]

result = a.includes(6)
console.log(result)   // false
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.includes(10)
let dateEnd = Date.now()
console.log(dateEnd - dateStart) // 0ms 0ms 0ms

a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.includes(10000000-1)
let dateEnd = Date.now()
console.log(dateEnd - dateStart) // 22ms 18ms 27ms 效能不錯
複製程式碼

27、map(fn)以fn函式中返回值組成新的陣列返回(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.map((v, i)=>{
  return 9
})
console.log(result)   // [9, 9, 9, 9, 9]
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.map(v=>1)
let dateEnd = Date.now()
console.log(dateEnd - dateStart) // 2158ms 2007ms 2079ms 耗時比較大
複製程式碼

28、reduce()累計器(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.reduce((accumulator, currentValue, currentIndex, array)=>{
  console.log(accumulator, currentValue, currentIndex, array)
  return accumulator + currentValue
  // 5  1 0 [1, 2, 3, 4, 5]  第一次accumulator的值為reduce第二個引數5, currentValue為陣列第一個元素
  // 6  2 1 [1, 2, 3, 4, 5]  第二次accumulator的值為5加上陣列a中的第一個值,即是第一次迴圈時return的值
  // 8  3 2 [1, 2, 3, 4, 5]  同上
  // 11 4 3 [1, 2, 3, 4, 5]  同上 
  // 15 5 4 [1, 2, 3, 4, 5]  同上
}, 5)
console.log(result)   // 20 為最終累計的和
console.log(a)        // [1, 2, 3, 4, 5]

// 無初始值時,accumulator的初始值為陣列的第一個元素,currentValue為陣列第二個元素
result = a.reduce((accumulator, currentValue, currentIndex, array)=>{
  console.log(accumulator, currentValue, currentIndex, array)
  return accumulator + currentValue
  // 1  2 1 [1, 2, 3, 4, 5]
  // 3  3 2 [1, 2, 3, 4, 5]
  // 6  4 3 [1, 2, 3, 4, 5]
  // 10 5 4 [1, 2, 3, 4, 5]
})
console.log(result)   // 15 為最終累計的和
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.reduce((accumulator, currentValue, currentIndex, array)=>{
  return accumulator + currentValue
})
let dateEnd = Date.now()
console.log(dateEnd - dateStart) // 200ms 258ms 257ms 效率與forEach相差也不多,而且比forEach多個累計的功能
複製程式碼

29、reduceRight()與reduce功能一樣,只是從陣列末尾開始進行累計(不改變原陣列)

略...
複製程式碼

30、some(fn)檢查陣列中是否含有滿足fn函式條件的值(不改變原陣列)

let a = [1, 2, 3, 4, 5]
let result = a.some((v)=>{
  return v > 2
})
console.log(result)   // true
console.log(a)        // [1, 2, 3, 4, 5]

result = a.some((v)=>{
  return v > 6
})
console.log(result)   // false
console.log(a)        // [1, 2, 3, 4, 5]

// Time
a = []
for(let i = 0; i < 10000000; i++) {
  a.push(i)
}
let dateStart = Date.now()
a.some(v=>{
  return v < 0
})
let dateEnd = Date.now()
console.log(dateEnd - dateStart)  // 171ms 176ms 188ms 全部不滿足的情況下效率與forEach相當
複製程式碼

31、toLocaleString()將陣列中的每個元素使用各自的toLocaleString()轉換後用,拼接(不改變原陣列)

let a = [1, new Date(), 'a', {m: 1}]
let result = a.toLocaleString()
console.log(result)   // '1,2018/10/3 下午9:23:59,a,[object Object]'
console.log(a)        // [1, Wed Oct 03 2018 21:23:59 GMT+0800 (中國標準時間), "a", {m: 1}]
複製程式碼

32、[@@iterator]()陣列自帶的迭代器方法(不改變原陣列)

使得陣列原生可以使用for...of進行遍歷
複製程式碼

相關文章