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
}

JS: 数组的循环函数的更多相关文章

  1. js数组的splice函数

    一直没搞懂数组的splice函数,今天稍微测试了一下,了解了它的功能,在这里记录一下 1.测试 测试① var a = [1,2,3]; console.info(a.splice(1,1)); co ...

  2. JS数组(Array)处理函数总结

    1.concat() 连接两个或更多的数组该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本.例如: <script type="text/javascript"&g ...

  3. js数组之可变函数

    在js的数组中有两个方法为数组添加元素:1.push();2.unshift(),push函数是将元素添加到数组的末尾,现在不用说大家估计也能猜出来,unshift这个函数就是把元素添加到数组的开头的 ...

  4. js数组,数字函数,字符串函数,表单验证,hashMap,堆栈,日期函数,call函数

    1.javascript的数组API Js代码 收藏代码 //定义数组 var pageIds = new Array(); pageIds.push('A'); 数组长度 pageIds.lengt ...

  5. js数组之sort()函数

    一般我们使用sort函数进行数组的排序,sort()方法有一个可选参数,是用来确定元素顺序的函数.如果这个参数被省略,那么数组中的元素将按照ASCII字符顺序进行排序.如: var arr = [&q ...

  6. js 数组的forEach 函数

    var numbers = [4, 9, 16, 25]; function myFunction(item, index) { console.log("item:" + ite ...

  7. js数组 函数

    js数组 filter(),map(),some(),every(),forEach(),lastIndexOf(),indexOf() 文章1:http://www.jb51.net/article ...

  8. js 数组常用的操作函数整理

    平时多做企业应用开发,抱着实用为主,对前端技术理解得比较肤浅,下面就是肤浅地对 js 数组的属性和方法及对它操作的 jquery 方法做些记录: js 数组是 js 内建的一个非常强大数据类型,由于 ...

  9. 页面循环绑定(变量污染问题),js面向对象编程(对象属性增删改查),js字符串操作,js数组操作

    页面循环绑定(变量污染问题) var lis = document.querySelectorAll(".ul li") for ( var i = 0 ; i < lis. ...

随机推荐

  1. 2019.01.21 bzoj2989: 数列(二进制分组+主席树)

    传送门 二进制分组入门题. 主席树写错调题2h+2h+2h+体验极差. 题意简述:给一堆点,支持加入一个点,询问有多少个点跟(x,y)(x,y)(x,y)曼哈顿距离不超过kkk. 思路:题目要求的是对 ...

  2. java常用设计模式三:原型模式

    在说原型模式之前先说一下浅拷贝和深拷贝的概念 一.浅拷贝和深拷贝 1.浅拷贝 在java中,对象创建后需要有一个引用变量来指向该对象实际的地址空间,也就是说引用变量与对象实体是两个不同的数据体.在Ob ...

  3. Mybatis-Plus 实战完整学习笔记(四)------全局参数配置

    一.全局配置设置 (1)全局配置Id自动生成 <!--定义mybatisplus全局配置--> <bean id="globalConfig" class=&qu ...

  4. svn 提交代码 自动过滤技巧

    操作 在用svn管理版本时,有时希望在提交到服务器时,能过滤掉指定后缀名的所有文件,或指定名称的文件夹.文件名. 常见的文件夹名称和文件名如下: bin obj debug temppe *.suo ...

  5. java 块语句 和引用类型

    1.java中存在块语句,块语句分为四种 1.静态块 2.普通块 3.构造块 4.同步块 静态块的执行时机是在class文件装载的时候;静态块只会执行一次, 多个静态块的时候,按出现顺序执行,存放类的 ...

  6. idea常用插件介绍

    常用插件 mybatis mapper 选择plugins,搜索mybatis plugin 激活教程 使用 插件的使用

  7. 关于Linux学习中的问题和体会

    本科期间未开展过与之相关的课程,所以初次接触Linux难免有些问题!参照老师给的学习资料中内容,逐步解决了一些问题,但还有一些问题没解决,下面列举出自己遇到的一些问题. 1.在环境变量与文件查找专题中 ...

  8. 基于SVG+AJAX的网页数据监控

    这个是前一阵做的一个火灾报警主机数据网页监控,前后台主要耗时5小时.绘图2小时,配置后端采集端1小时,测试2小时. 用的SVG,上面画的指示灯可以实时显示传感器的状态. 用开源方案实现. 如果集成到自 ...

  9. POJ3169--Layout(SPFA+差分系统)

    Description Like everyone else, cows like to stand close to their friends when queuing for feed. FJ ...

  10. POJ3111 K Best 2017-05-11 18:12 31人阅读 评论(0) 收藏

    K Best Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 10261   Accepted: 2644 Case Time ...