JS: 數組的循環函數

JS 數組相關的循環函數,用得挺多,因此有些坑仍是要去踩一下,先來看一道面試題。javascript

注意:下面提到的不改變原數組僅針對基本數據類型。java

面試題


模擬實現數組的 map 函數。面試

心中有答案了嗎?個人答案放在最後。數組

map( callback( cur, index, arr ), thisArg )


map 方法建立一個新數組,其結果是該數組中的每一個元素都調用一個提供的函數後返回的結果。函數

  1. map 不改變原數組(能夠在 callback 執行時改變原數組)測試

    let a = [1, 2, 3]
    let b = a.map(item => item*2)
    
    // 不改變原數組
    a // [1, 2, 3]
    b // [2, 4, 6]
    
    // 在 callback 執行時改變原數組
    a.map((cur, i, arr) => arr[i] *= 2)
    a // [2, 4, 6]
  2. 沒有 return 時,返回undefinedthis

    let c = a.map((cur, i, arr) => arr[i] *= 2)
    
    c // [undefined, undefined, undefined]
  3. 原數組中新增長的元素不會被 callback 訪問prototype

    let a = [1, 2, 3]
    let b = a.map((cur, i, arr) => {
      arr.push(arr.length + 1)
      return cur*2
    })
    
    b // [2, 4, 6]
    a // [1, 2, 3, 4, 5, 6]

filter( callback( cur, index, arr ), thisArg )


filter 方法建立一個新數組, 其包含經過所提供函數實現的測試的全部元素。code

這個沒什麼好說的,filter 只返回過濾後的新數組,依然不會改變原數組索引

let a = [1, 2, 3]
let b = a.filter(item => item % 2 == 0)

a // [1, 2, 3]
b // [2]

須要注意的是,儘可能不要在 filter 中直接return item

/* 通常狀況是沒問題的 */
let a = [1, 2, 3]
let b = a.filter(item => item)

a // [1, 2, 3]
b // [1, 2, 3]

/* false、0、undefined、null */
let c = [true, false, 0, undefined, null]
let d = c.filter(item => item)

c // [true, false, 0, undefined, null]
d // [true]

通常狀況下直接return item是沒問題的,但遇到false、0、undefined、null這幾個特殊值時,就會出問題。由於 filter 是根據return的值來判斷返回的新數組是否要添加遍歷到的原數組索引值,而不是直接在新數組中添加return的值。

簡單來講,就是 filter 中的 callback 的 return 應該返回一個 boolean 值,true 即知足過濾條件,false 則不知足過濾條件。

forEach( callback( cur, index, arr ), thisArg )


forEach 方法對數組的每一個元素執行一次提供的函數。

  1. forEach 沒法中斷,須要中斷的則代表:不該該使用 forEach。固然,使用 try、catch 是能夠實現中斷的,但不推薦。

    let a = [1, 2, 3]
    
    try {
      a.forEach(item => {
        console.log(item)
       if (item % 2 == 0) throw new Error('hhh')
      })
    } catch (e) {
      console.log('中斷')
    }
    
    /*
    1
    2
    中斷
    */
  2. forEach 也是不會改變原數組的

    let a = [1, 2, 3]
    a.forEach(item => item*2)
    a // [1, 2, 3]

every( callback( cur, index, arr ), thisArg )


every 方法測試數組的全部元素是否都經過了指定函數的測試。

這個沒什麼好說的,但 every 和 some 都有個坑。

:空數組調用 every 會返回true

// 返回了 true
[].every(item => item > 0) // true

some( callback( cur, index, arr ), thisArg )


some 方法測試是否至少有一個元素經過由提供的函數實現的測試。

:空數組調用 some 會返回false

// 和 every 相反,這裏返回了 false
[].some(item => item > 0) // false

reduce( callback( prev, cur, index, arr ), initVal )


reduce 方法對數組中的每一個元素執行一個由您提供的reducer函數(升序執行),將其結果彙總爲單個返回值。

  1. 若是沒有提供initVal,reduce 會取數組中的第一個值爲prev, 而後從數組索引 1 開始執行 callback,跳過第一個索引。若是提供initlVal,從索引 0 開始,previnitVal

  2. 若是數組爲空且沒有提供initVal會報錯。

    [].reduce((prev, cur)=> cur) // TypeError

實現 map 函數


Array.prototype._map = function(callback, thisArg) {
  if (typeof callback !== 'function') {
    throw new TypeError(`${callback} is not a function`)
  }
  
  let res = []
  
  for (let i=0; i<this.length; i++) {
    res.push(callback.call(thisArg, this[i], i, this))
  }
  
  return res
}
相關文章
相關標籤/搜索