盤點那些常見的 JS 數組方法及 Polyfill

前言

雖然有時候遍歷數組只須要 for 循環則足矣,可是若是 API 利用得當,每每能更大程度的提升代碼的可讀性,減小心智負擔~javascript

常見的數組 API

Array.prototype.some

功能

判斷數組中是否至少有一個項經過了預設的條件,結果返回 boolean前端

參數

  • callback:執行的回調函數,用於條件判斷。
  • thisArg:執行函數的 this 指針。

場景

判斷數組 [ 1, 2, 3, 5, 6, 7 ] 中是否存在偶數java

const target = [ 1, 2, 3, 5, 6, 7 ]
if (target.some(a => a % 2 === 0)) {
    // do something   
}

Polyfill

Array.prototype.some = function(fn, thisArg) {
    // 異常處理
    if (this == null) {
        throw new TypeError('Cannot read property of null or undefined.')
    }
    if (typeof fn !== 'function') {
        throw new TypeError(`${fn} must be a function.`)
    }
    // 須要用 Object 包裝一次 this
    const O = Object(this)
    const len = O.length || 0
    for (let i = 0; i < len; i++) {
        if (i in O) {
            if (fn.call(thisArg, O[i], i, O)) {
                return true
            }
        }
    }
    return false
}

Array.prototype.every

功能

判斷數組中是否所有項都經過了預設的條件,結果返回 boolean數組

參數

  • callback:執行的回調函數,用於條件判斷。
  • thisArg:執行函數的 this 指針。

場景

判斷數組 [ 1, 2, 3, 5, 6, 7 ] 是否每一個數都是偶數。微信

const target = [ 1, 2, 3, 5, 6, 7 ]
if (target.every((num) => num % 2 === 0)) {
  // do something
}

Polyfill

Array.prototype.every = function(fn, thisArg) {
  // 異常處理
  if (this == null) {
    throw TypeError('Cannot read property of null or undefined')
  }
  if (typeof fn !== 'function') {
    throw TypeError(`${fn} is not a function`)
  }
  // 從新包裝一次 this
  const O = Object(this)
  const len = O.length || 0
  for (let i = 0; i < len; i++) {
    if (i in O) {
      if (!fn.call(thisArg, O[i], i, O)) {
        return false
      }   
    }
  }
  return true
}

Array.prototype.slice

功能

淺拷貝數組,能夠指定開始和結束下標來對數組某段作拷貝。若是不添加任何參數,那麼會直接拷貝整個數組。函數

參數

  • begin(可選參數): 從這個下標開始拷貝,若是爲負數,則表示從倒數第 begin 開始拷貝。
  • end(可選參數): 從這個下標結束拷貝,若是爲負數,則表示從倒數第 end 結束拷貝。

場景

拷貝數組 [ 1, 2, 3, 5, 6, 7 ] 到另一個數組。this

const target = [ 1, 2, 3, 5, 6, 7 ]
const temp = target.slice()

Polyfill

Array.prototype.slice = function(begin, end) {
      if (this == null) {
          throw new TypeError('cannot read property of null or undefined')
      }
      
      // 若是 end 沒有傳就默認截到數組末尾
      end = (typeof end !== 'undefined') ? end : this.length

      const cloned = []
      const len = this.length
      let i = 0

      // 處理下 begin 參數
      let start = begin || 0
      start = (start >= 0) ? start : Math.max(0, len + start)

      let upTo = (typeof end == 'number') ? Math.min(end, len) : len
      if (end < 0) {
        upTo = len + end
      }
    
      // 計算 upTo 到 start 之間的差值
      let size = upTo - start
    
      // 若是 size > 0 就計算
      // 再拷貝到 cloned 數組中
      if (size > 0) {
        for (i = 0; i < size; i++) {
          cloned[i] = this[start + i]
        }
      }

      return cloned
    };

Array.prototype.reduce

功能

對數組中的每一個元素執行一個由您提供的reducer函數,將其結果彙總爲單個返回值。prototype

參數

  • callback指針

    • accumulator
    • currValue
    • index
    • array(調用 reduce 的數組)
  • initValue

場景

計算數組 [ 1, 2, 3, 5, 6, 7 ] 的和。code

const target = [ 1, 2, 3, 5, 6, 7 ]
const sum = target.reduce((prev, curr) => prev + curr)

Polyfill

Array.prototype.reduce = function(fn, initValue) {
    // 異常判斷
    if (this == null) {
        throw new TypeError('Cannot read property of null or undefined')
    }
    if (typeof fn !== 'function') {
        throw new TypeError(`${fn} must be a function`)
    }
    const O = Object(this)
    const len = O.length || 0
    let i = 0
    let k = 0
    let accumulator = initValue
    // 遍歷並拿到結果
    while (i < len) {
        if (i in O) {
            if (!accumulator) {
                accumulator = O[i]
            } else {
                accumulator = fn.call(this, accumulator, O[i], i, O)
            }
        } else {
            k++
        }
        i++
    }
    // 空數組異常判斷
    if (k >= len) {
        throw new TypeError('Reduce of empty array with no initial value')
    }
    return accumulator
}

Array.prototype.map

功能

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

參數

  • callback

    • currentValue
    • index
    • array
  • thisArg

場景

將數組 [ 1, 2, 3, 5, 6, 7 ] 轉化成對象數組,格式爲 [{val: 1}, ...]

const target = [ 1, 2, 3, 5, 6, 7 ]
const objArr = target.map((num) => {
    return {
        val: num
    }
})

Polyfill

Array.prototype.map = function(fn, thisArg) {
    // 異常判斷
    if (this == null) {
        throw new TypeError('Cannot read property of null or undefined.')
    }
    if (typeof fn !== 'function') {
        throw new TypeError(`${fn} is not a function.`)
    }
    const O = Object(this)
    const len = O.length || 0
    const res = []
    // 遍歷並拿到結果
    for (let i = 0; i < len; i++) {
        if (i in O) {
            res.push(fn.call(thisArg, O[i], i, O))
        }
    }
    return res
}

總結

看完上面這些 Polyfill 以後,咱們能夠找到一些規律,以便遇到沒見過的 Polyfill 也能寫出個大概:

  • this 指針和傳入的回調函數作異常判斷
  • thisObject 從新包裝一層
  • 具體的邏輯處理,每一個函數都不太同樣
  • 返回結果

參考資料

搜索「tony老師的前端補習班」關注個人微信公衆號,那麼就能夠第一時間收到個人最新文章。

相關文章
相關標籤/搜索