zoukankan      html  css  js  c++  java
  • JS: 数组的循环函数

    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
    }
    
  • 相关阅读:
    __setattr__,__getattr__,__delattr__
    LeetCode 面试题42. 连续子数组的最大和
    LeetCode 53. 最大子序和
    LeetCode 面试题39. 数组中出现次数超过一半的数字
    LeetCode 169. 多数元素
    LeetCode 426.将二叉搜索树转化为排序的双向链表
    LeetCode 面试题36. 二叉搜索树与双向链表
    LeetCode 面试题35. 复杂链表的复制
    LeetCode 138. 复制带随机指针的链表
    LeetCode 面试题34. 二叉树中和为某一值的路径
  • 原文地址:https://www.cnblogs.com/guolao/p/10677361.html
Copyright © 2011-2022 走看看