1
头图

前言

虽然有时候遍历数组只需要 for 循环则足矣,但是如果 API 利用得当,往往能更大程度的提高代码的可读性,减少心智负担~

常见的数组 API

Array.prototype.some

功能

判断数组中是否至少有一个项通过了预设的条件,结果返回 boolean

参数

  • callback:执行的回调函数,用于条件判断。
  • thisArg:执行函数的 this 指针。

场景

判断数组 [ 1, 2, 3, 5, 6, 7 ] 中是否存在偶数

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 ] 到另外一个数组。

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函数,将其结果汇总为单个返回值。

参数

  • callback

    • accumulator
    • currValue
    • index
    • array(调用 reduce 的数组)
  • initValue

场景

计算数组 [ 1, 2, 3, 5, 6, 7 ] 的和。

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老师的前端补习班」关注我的微信公众号,那么就可以第一时间收到我的最新文章。


tonychen
1.2k 声望272 粉丝