forEach、map、filter、find、sort、some等易错点整理

forEach、map、filter、find、sort、some等易错点整理

  最近手头上做了一个很大的后台管理项目,前端对复杂数据的处理要求颇高,也确实让自己发现了很多之前被忽视的细节。在此特整理出来,希望不熟悉的朋友们们以后可以绕开我踩的这些坑。本文初衷在于帮助大家梳理一些数组操作上的重点和易错点,希望也能帮助和提醒大家,我会尽可能写的幽默些,加深大家的记忆。水平有限,真心无限。希望大家喜欢,本文很基础很基础,请大神绕道,谢谢。。。我不知道为什么成了热门。。。

一、常用方法解析

  说起数组操作,我们肯定第一反应就是想到forEach()、map()、filter()等方法,下面分别阐述一下各方法的优劣。

1、forEach

1.1 基础点

  forEach的使用频率很高,多用于对数组自身的改变和各元素相关统计性的计算,重要特性如下:

  1. 可以改变数组自身,没有返回值;
  2. 中途不能用常规操作跳出循环,可以用抛出异常(try/catch)的方式,但不推荐这样做;

1.2 易错点

  1. forEach()不一定改变自身数组。我们可以看看数组中的元素是值类型和引用类型场景下,是否都能获得改变:
var arr1 = [
   {name:'鸣人',age:16},
   {name:'佐助',age:17}
];
var arr2 = [1,2,3];

arr1.forEach(item => { 
  item.age = item.age + 1}
);

//=> [{name:'鸣人',age:17},{name:'佐助',age:18}]

arr2.forEach(item => {
  item = item * 2}
)

// => [1,2,3]
复制代码

最后的结果是,arr1发生了改变,鸣人、佐助都长了一岁,arr2没有任何改变。所以,可以粗暴得出结论:当数组中元素是值类型,forEach绝对不会改变数组;当是引用类型,则可以改变数组

  1. 不支持链式操作,所以以下代码是错误的:
[1,2,3,4,5].forEach(
   item => console.log(item)
).filter(item => { 
   return item > 2 
})
// Uncaught TypeError: Cannot read property 'filter' of undefined
复制代码

注意这里我们说仅仅是forEach()这个方法不支持链式调用,在调用forEach之前,前面的数组你怎么玩链式都没问题,最后返回一个正常数组即可:

// 这个没问题
[1,2,3,4,5].filter(item => { 
  return item > 2 
}).forEach(item => {
   console.log(item) 
})
复制代码
  1. 不会在迭代之前创建数组的副本,这个使用场景太少太少了,忽略了...

2、map

  map()功能很强大,forEach()的一些局限性它很多都能解决。"map"即"映射",也就是原数组被"映射"成对应新数组。

2.1 基础点

  1. 新建一个数组,需要有承载对象,也意味着原始数组在调用它后不会发生变化;
  2. 该数组中的每个元素都调用一个提供的函数后返回结果。

2.2 易错点

  1. 创建新数组不代表不能用它改变原有数组,你用原有数组去承载就可以:
let arr = [1,2,3];
arr = arr.map(item => { return item * 2 })
复制代码

arr同样也会改变,所以这也不费事嘛。。。

  1. map()中每个元素都要执行相应的回调函数,所以必须要有return(千万别学某些人,判断过程一复杂,忘了return,最后得到的是个空数组,哭天喊地的~~~),如果你想给数组做一定的过滤处理,那map()基本上行不通:
let newArr = [1,2,3,4,5].map(item => { if(item > 3) return item })
// => [undefined, undefined, undefined, 4, 5]
复制代码

最终得到的结果是[undefined, undefined, undefined, 4, 5]。别和我说你简单处理一下就能凑合用, 人生不能凑合,代码也是!

3、filter

  map()没法做到的过滤,就交给filter()去完成,这个大家肯定也都知道。filter()和map()很像,就像周董《东风破》和《发如雪》一样像,也是创建一个新数组,新数组中的元素是筛选出来的符合条件的所有对象。简单写个例子:

let newArr = [1,2,3,4,5].filter(item =>{
   if(item > 3) return item 
})
//  => [4,5]
复制代码

这个相信也没啥易错点,有的话欢迎评论指出~~~

4、sort()

sort()用于对数组的元素进行排序。排序顺序可以是字母或数字,并按升序或降序。

4.1 基础点

1.默认排序按字母升序(更准确一些是根据字符串Unicode码点):

[3,4,2,1,5].sort()
// => [1,2,3,4,5]

['Javascript','Vue','React','Node','Webpack'].sort();
// => ["Javascript", "Node", "React", "Vue", "Webpack"]
复制代码

4.2 易错点

  1. sort()与map()、filter()等不同,它直接改变原始数组(很重要!);

  2. 如果想按照其他标准进行排序,就需提供比较函数compareFunction(a,b),数组会按照调用该函数的返回值排序,即a和b是两个将要比较的元素:

  • 如果compareFunction(a,b)小于0,则a排列到b之前;
  • 如果 compareFunction(a, b)等于0,a和b的相对位置不变(并不保证);
  • 如果 compareFunction(a, b)大于0,b排列到a之前; 直接上例子:
let Users = [
  {name:'鸣人',age:16},
  {name:'卡卡西',age:28},
  {name:'自来也',age:50},
  {name:'佐助',age:17}
];
Users.sort((a,b)=> {
   return a.age - b.age
})

// => 鸣人、佐助、卡卡西、自来也
复制代码

5、some()

some()也是很好的一个方法,用于检查数组中是否有某些符合条件。

5.1 基础点

  1. 只要有一个满足即返回true,之后的不再执行(所以说对性能很友好!)。
var result = [
   {name:'鸣人',age:16},
   {name:'佐助',age:17}
].some(item => {
	return item.age > 16 
});
=> true
复制代码

5.2 易错点

  some()和下面讲的every()返回的都是Boolean值,仅此而此,别多想......

6、every()

  如果说some()是"||"判断,那every()就是"&&"判断,它用于检测数组中的每一项是否都满足条件,只有都满足了才会返回true。这点也很好理解:

var result = [
   {name:'鸣人',age:16},
   {name:'佐助',age:17}
].every(item => {
	return item.age > 16 
});
=> false
复制代码

二、其他经典方法

  在我们的日常工作中,会有很多业务需求是上述方法做不到的,比如下面三个需求:

  1. 给一个数组做去重处理;
  2. 判定当前数组里是否有某个元素,并返回该元素;
  3. 判定当前数组里是否有某个元素,并把它去除;

针对需求1,我相信看到"去重",你肯定会想到new Set(),这也是个经常出现的面试题;针对需求2,当你看到判定当前数组中是否有某个元素,也许会说filter() 不就是干这脏活累活的吗? 还真不是,不信,我们分别展开讨论一下吧。

1. 数组去重(没你想的那么简单)

1.1 new Set() 的局限性

  数组去重,基本上论坛上各位大神的面试题里都会有这个,没错,正是new Set(),很经典的办法,面试必备:

let tempArr = new Set([1,2,3,3,4,4,5])
// => {1,2,3,4,5} 

//并且已有元素是添加不进去的:
tempArr.add(3) 
// => {1,2,3,4,5}

tempArr.add(6)
// => {1,2,3,4,5,6}
复制代码

恩,很棒,一定注意new Set()会将结果转换成对象!但实际工作中我们很少会和元素是值类型的数组打交道,那看看元素是引用类型还行不行:

let mySet = new Set();
mySet.add(1); // Set(1) {1}
mySet.add(5); // Set(2) {1, 5}
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性
mySet.add('some text'); 
[...mySet]
// => [1,5,'some text']

mySet.add({name:'jay Chou',age:40});
mySet.add({name:'jay Chou',age:40});

[...mySet]
// => [1,5,'some text',{name:'jay Chou',age:40},{name:'jay Chou',age:40}]
复制代码

看到了吧,Set()没法去重元素是引用对象的数组。那接下来咋整呀?

1.2 _.uniqWith()

别担心,Lodash帮我们,Lodash是一个一致性、模块化、高性能的JavaScript实用工具库。它有提供给了我们一个很好的方法——_.uniqWith():

import _ from 'lodash';
<script>
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
_.uniqWith(objects, _.isEqual);
</script>

//=> [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
复制代码

其中, _.isEqual(value,other)用于执行深比较来确定两者的值是否相等。 _.uniqWith()做去重处理。

2. 获取数组中的指定元素

  在工作中我们还有一个比较常见的场景,就是在数组中找到我想要的那一个,并且返回给我。好的,some()已经办不到了,它只会告诉我是否存在,filter()确实可以做到,但是如果我本身就知道这个数组里即使有我想的那个,也肯定只有一个,不可能出现多个,所以,出于性能的考虑,我不想用filter()给我从头遍历到尾,这样怎么办?

2.1 findIndex()

  好了,既然filter()不支持中断遍历,那我们就要找一个能中断遍历的方法,我们可以使用for...of,该方法支持中断遍历,但是该方法代码量较大,不建议使用,感兴趣的同学可以查阅一下。针对这个场景,我们可以使用 findIndex()帮我们先获取到所需元素的索引值,拿到索引后,你要杀要剐随你便

let testArr = [{name:'鸣人',age:16},{name:'佐助',age:17},{name:'卡卡西',age:26}]
let index = testArr.findIndex(item => { return item.age > 16 });
// => 1
复制代码

或者也可以使用Lodash提供的_.findIndex(),通过对象属性值直接获取对应索引:

let testArr = [{name:'鸣人',age:16},{name:'佐助',age:17},{name:'卡卡西',age:26}]
let index = _.findIndex(testArr, {name:'佐助'});
// => 1
复制代码

注意:IE 11 及更早版本不支持findIndex() 方法。所以,如果对浏览器兼容有要求,那就用Lodash的 _.findIndex()

2.2 find()

  find()顾名思义,就是用来在数组中找到我们所需要的元素,并且和some()一样,只要有一个满足即返回该元素,不会多余遍历,对性能很友善。

let testArr = [{name:'鸣人',age:16},{name:'佐助',age:17},{name:'卡卡西',age:27},{name:'佐助',age:17}]
let result = testArr.find(item => { return item.name == '佐助'});
// => { name:'佐助',age:17 }
复制代码

但是!很遗憾IE 11 及更早版本也不支持 find()。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值