欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JS: 数组的循环函数

程序员文章站 2022-03-20 19:53:04
JS 数组相关的循环函数,用得挺多,所以有些坑还是要去踩一下,先来看一道面试题。 注意: 下面提到的不改变原数组仅针对基本数据类型。 面试题 模拟实现数组的 map 函数。 心中有答案了吗?我的答案放在最后。 map( callback( cur, index, arr ), thisArg ) m ......

js 数组相关的循环函数,用得挺多,所以有些坑还是要去踩一下,先来看一道面试题。

注意:下面提到的不改变原数组仅针对基本数据类型。

面试题


模拟实现数组的 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 时,返回undefined

    let c = a.map((cur, i, arr) => arr[i] *= 2)
    
    c // [undefined, undefined, undefined]
  3. 原数组中新增加的元素不会被 callback 访问

    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 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

这个没什么好说的,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
}