更优雅的编写JavaScript,使用这些函数秒变大神

article/2025/9/30 13:29:48

JavaScript中更简便的数组处理函数.map(),.reduce(),.filter()

如果你刚接触JavaScript可能你还没有听说过.map().reduce().filter()。或者听说过,看过别人用过但是自己在实际项目中没有用过。在国内很多开发项目都是需要考虑IE8的兼容,为了兼容很多JavaScript好用的方法和技巧都被埋没了。但是我发现近几年开始,很多开发项目已经完全抛弃了IE这个魔鬼了。如果你不需要兼容“石器时代”的IE浏览器了,那就要开始熟悉一下这几个方法来处理数组。

注意这遍文章说的的3个方法其实在很多其他语言都可以使用到,因为这几个方法和使用概念在很多其他语言都是存在的。


.map()

让我用一个简单的例子告诉你如何使用这个方法。假如你现在有多对象的数组数据 - 每一个对象代表着一个员工的信息。现在你想要的最终结果就是取出所有员工的唯一ID值。

// 员工数据
var employees = [{ id: 20, name: 'Captain Piett' },{ id: 24, name: 'General Veers' },{ id: 56, name: 'Admiral Ozzel' },{ id: 88, name: 'Commander Jerjerrod' }
];
// 你想要的结果
[20, 24, 56, 88]

其实要实现这个结果有很多数组处理方式。传统的处理方法就是先定义一个空数组,然后使用.forEach().for(...of),或者是最简单的.for()来组装ID到你定义的数组里面。

我们来对比一下传统的处理方式和.map()的区别。

使用.forEach()

var employeeIds = [];
employees.forEach(function (employee) {employeeIds.push(officer.id);
});

注意使用传统的方式,我们必须有一个预定义的空数组变量才行。但是如果是.map()就会更简单了。

var employeeIds = employees.map(function (employee) {return employee.id
});

甚至我们可以用更简洁的方式,使用箭头方法(但是需要ES6支持,Babel,或者TypeScript)。

const employeeIds = employees.map(employee => employee.id);

所以.map()到底是怎么运作的呢?这个方法有两个参数,第一是回调方法,第二是可选内容(会在回调方法中做为this)。数组里的每个数值/对象会被循环进入到回调方法里面,然后返回新的数值/对象到结果数组里面。

注意结果数组的长度永远都会和被循环的数组的长度一致。


.reduce()

.map()相识,.reduce()也是循环一个回调方法,数组里面的每一个元素对回进入回调方法。区别是回调方法返回的值会被传递到下一个回调方法,如此类推(等同于一个累加器)。

.reduce()里的累加值可以是任何属性的值,包括integerstringobject等等。这个累加值会被实力化或者传递到下一个回调方法。

来上代码,做个简单的例子!假如你有一个飞机师的数组,数组里面有每个飞机师的工龄。

var pilots = [{id: 10,name: "Poe Dameron",years: 14,},{id: 2,name: "Temmin 'Snap' Wexley",years: 30,},{id: 41,name: "Tallissan Lintra",years: 16,},{id: 99,name: "Ello Asty",years: 22,}
];

现在我们需要知道所有飞机师累计的总工龄。使用.reduce()就是比吃饭还简单的事情。

var totalYears = pilots.reduce(function (accumulator, pilot) {return accumulator + pilot.years;
}, 0);

注意我这里第二个参数我传了0。第二个参数是一个累加值的初始值。当然如果场景需要这个初始值也可以传入一个变量或者你需要的值。循环了数组里的每一个元素后,reduce方法会返回最终累加后的值(在我们这个例子中就是82)。

例子里面的accaccumulator就是累加值变量

如果是使用ES6箭头写法,我们可以写的更加优雅简洁。一行就可以搞掂的事情!

const totalYears = pilots.reduce((acc, pilot) => acc + pilot.years, 0);

现在如果我们需要找到哪一位是最有经验的飞机师。这种情况我们一样可以使用.reduce()

var mostExpPilot = pilots.reduce(function (oldest, pilot) {return (oldest.years || 0) > pilot.years ? oldest : pilot;
}, {});

这里我把accumulator变量改为oldest代表飞机师里面的老司机。这时候reduce里面的回调方法对比每一个飞机师,每一次飞机师的值进入这个回调方法,工龄更高的就会覆盖oldest变量。最终循环后得到的oldest就是工龄最高的飞机师。

通过这几个例子,你可以看到使用.reduce()可以简单又优雅的在一个数组里面获取到单个最终值或者对象。


.filter()

如果你现在的场景是需要在一个数组里面过滤一部分的数据,这个时候.filter()就是你的最好的朋友了。

我们用回飞机师的数据,并且加入了所属航空公司的值:

var pilots = [{id: 2,name: "Wedge Antilles",faction: "Rebels",},{id: 8,name: "Ciena Ree",faction: "Empire",},{id: 40,name: "Iden Versio",faction: "Empire",},{id: 66,name: "Thane Kyrell",faction: "Rebels",}
];

加入现在我们想分别筛选出RebelsEmpire两个航空公司的飞机师,使用.filter()就是轻而易举的事情!

var rebels = pilots.filter(function (pilot) {return pilot.faction === "Rebels";
});
var empire = pilots.filter(function (pilot) {return pilot.faction === "Empire";
});

就这么简单,如果使用箭头方法(ES6)就更加优雅了:

const rebels = pilots.filter(pilot => pilot.faction === "Rebels");
const empire = pilots.filter(pilot => pilot.faction === "Empire");

其实原理很简单,只要你的回调方法返回的是true,这个值或者对象就会在新的数组里面了。如果返回的是false就会被过滤掉了。


结合使用 .map(),.reduce(),.filter()

既然我们刚刚学到的三个函数都是可以用于数组的,并且.map().filter()都是返回数组的。那我们就可以串联起来使用。不说多了上代码试试!

我们用一个有趣一点的数据试验一下,假如现在我们有一个星球大战里面的人物的数组。每个字段的定义如下:

  • Id: 人物唯一ID
  • name: 人物名字
  • pilotingScore: 飞行能力指数
  • shootingScore: 射击能力指数
  • isForceUser: 是否拥有隔空操控能力

我们的目标:获取拥有隔空操控能力的飞行员的总飞行能力指数。我们先分开一步一步实现这个目标!

  • 首先我们需要先获取到拥有隔空操控能力的飞行员。
var jediPersonnel = personnel.filter(function (person) {return person.isForceUser;
});
// 结果集: [{...}, {...}, {...}] (Luke, Ezra and Caleb)
  • 这段代码我们获得了3个飞行员对象,分别都是拥有隔空操控能力的飞行员。使用这个对象我们来获取每个飞行员的飞行能力指数值。
var jediScores = jediPersonnel.map(function (jedi) {return jedi.pilotingScore + jedi.shootingScore;
});
// 结果: [154, 110, 156]
  • 获取到每个飞行员的飞行能力指数值后,我们就可以用累加器(.reduce())获取总飞行能力指数了。
var totalJediScore = jediScores.reduce(function (acc, score) {return acc + score;
}, 0);
// 结果: 420

这里分开实现方式可以达到我们的目标,但是其实我们可以串联起来,可以写的更加简洁又优雅!我们来玩玩更好玩的吧!

var totalJediScore = personnel.filter(function (person) {return person.isForceUser;}).map(function (jedi) {return jedi.pilotingScore + jedi.shootingScore;}).reduce(function (acc, score) {return acc + score;}, 0);

这样写是不是很优雅!都被这段代码给美到了!❤️

如果我们使用箭头写法ES6,就更加优雅了!

const totalJediScore = personnel.filter(person => person.isForceUser).map(jedi => jedi.pilotingScore + jedi.shootingScore).reduce((acc, score) => acc + score, 0);

哇!代码原来可以写的那么优雅的么?!想不到吧?

其实我们只需要使用.reduce()就可以得到我们的目标结果了,以上例子做为教学例子,所以使用了3个我们学到的函数。

我们来看看只用.reduce()怎么实现的,来我们一起来刷新一下三观吧!

const totalJediScore = personnel.reduce((acc, person) => person.isForceUser ? acc + person.pilotingScore + person.shootingScore : acc, 0);

不敢想象吧?一行就搞定一个功能不是梦!


为什么抛弃 .forEach()?

其实我一开始写前端的时候也是一顿撸,来个数组都是撸个for循环,解决一切数组处理问题。但是近几年我开始步入前后端开发,API接口对接。发现数据处理越来越多,如果还是像以前那样什么都用for循环来处理数据,那其实数据处理的代码就会越来越臃肿越来越复杂凌乱。所以我开始抛弃了.forEach()。开始做一个优雅的程序员!

为什么使用.map().filter().reduce()写代码更优雅,更美观呢?我们用一个实战例子来对比一下吧。

假设现在我们对接一个接口,返回的数组里面有两个字段name:人的名称title:对应的职位

var data = [{name: "Jan Dodonna",title: "General",},{name: "Gial Ackbar",title: "Admiral",},
]

产品经理给到你的需求是只需要展示这些人的职位称呼。

当然这个时候有一些前端就会说“我只是个小小的前端,后端给我处理吧”。但是,这个接口其实是一个通用的接口,就是获取这些员工的资料的,是在多个地方使用的。如果每一个页面因为需要展示的不一样而要写多一个接口给你,你觉得这样好吗?做为一个优秀的前端工程师🦁️,这种小case你自己就可以很优雅的处理好了。而且,在一个优秀的团队,后端确实是要考虑接口通用性的,这种为了你的方便而给他们带来更臃肿的接口是不可接受的。所以前端这个时候就是要重组数据了。

假设现在产品给你的需求是员工列表中,要支持只展示员工职称和员工信息的两种显示项。这个时候我们就要编写一个数据组装方法来跟进展示要求来改变数据格式。

因为这个“骚“需求,我们使用.forEach()来重组数据就相对比较麻烦了,而且代码也会变得臃肿。

我们忽略了组装数据的方法,直接就当作我们已经写好了一个组装数据的方法为formatElement。如果我们用forEach,那首先就需要定义一个空数组来接收结果。

var results = [];
data.forEach(function (element) {var formatted = formatElement(element);results.push(formatted);
});

所以我们需要两个方法才能实现这个数据结果,但是为什么要写的那么臃肿呢?因为forEach并没有返回值,单单就给你跑个循环,还需要自己push值到预定义的变量里面。其实一个方法就可以完成了,而且重点是一行代码就完事了。

来使用我们新学的技巧,用.map()来实现就非常简单优雅了。

var results = data.map(formatElement);

总结

你学会了吗?学会了就去尝试用.map().reduce().filter()来替换你传统的for循环吧!我保证你的代码会越来越简洁,可读性更高。

如果你喜欢我的这遍文章,记得继续关注我的博客,下一遍文章我们开学习怎么在JavaScript中使用.some().find()

坚持做一个优雅的程序员,坚持每天敲代码!

和你一起终身学习


http://chatgpt.dhexx.cn/article/Fk5xDAyC.shtml

相关文章

JavaScript 计算标准体重的公式

判断标准体重 世卫计算方法: 男性:(身高cm-80)70﹪标准体重 女性:(身高cm-70)60﹪标准体重 标准体重正负10﹪为正常体重 标准体重正负10﹪~ 20﹪为体重过重或…

ping命令显示时间

awk显示ping的时间ping 127.0.0.1 | awk { print $0"\t" strftime("%Y-%m-%d %H:%M:%S",systime()) } 注释:\t //换行字符 $0 //打印整行{print $0 "\t"} //逐行打印 strftime()//时间函数。一般配合系统时间函…

Linux Command date 显示时间

Linux Command date 显示时间 文章目录 Linux Command date 显示时间1. 简介2. 参数3. 日期格式4. 实例 1. 简介 命令功能&#xff1a;date 可以用来显示或设定系统的日期与时间。 2. 参数 -d<字符串>&#xff1a;显示字符串所指的日期与时间。字符串前后必须加上双引…

网页显示时间代码

网页显示时间代码如下&#xff1a; <test.html> <html> <body> <SCRIPT languagejavascript> function CurentTime(){var now new Date();var hh now.getHours();var mm now.getMinutes();var ss now.getTime() % 60000;var ms ss % 1000;ss (s…

android 显示系统时间,Android 实时获取当前时间并显示

1、首先创建子线程与主线程进行数据交互的Handler &#xff0c;并更新UI SuppressLint("HandlerLeak") private Handler mHandler new Handler() { Override public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_TIME: String time (String…

用Android studio完成简单的显示时间

用用Android studio完成简单的显示时间&#xff0c;并完成基础的布局改变&#xff0c;如字体大小&#xff0c;字体颜色等等问题。 在value中&#xff0c;颜色设置&#xff0c;可以自定义颜色。 dimens中完成字体大小的设置。 完成日历设置&#xff1a; package com.qst.Ca; im…

windows系统ping包显示时间(绝对好用)

使用管理员加打windows10中的Windows PowerShell&#xff0c;使用以下命令开始ping 例如ping192.168.0.1&#xff1a; ping.exe -t 192.168.0.1 |Foreach{"{0} - {1}" -f (Get-Date),$_}运行效果&#xff1a; 如果要ping又要记录到文本文档&#xff1a; ping.ex…

HTML页面显示时间——网页数字时钟、钟表

HTML页面显示时间——网页数字时钟、钟表 一个HTML网页上动态显示系统时间&#xff0c;可以使用javascript的Date对象&#xff0c;在javascript中new 一个date对象&#xff0c;并且根据这个date对象获取相应的时间日期的具体日期时间&#xff0c;比如 年 月 日 时分秒&#xff…

怎么将计算机工具栏时间去除,电脑任务栏不显示日期只显示时间的详细处理方法...

通常情况下&#xff0c;电脑右下角是会同时显示日期和时间的&#xff0c;这样可以方便我们查看。可是最近有用户在使用电脑时&#xff0c;却遇到了任务栏不显示日期只显示时间的问题&#xff0c;不知道怎么回事&#xff0c;更加不清楚如何解决&#xff0c;那么对于这一情况&…

Linux之history命令显示时间和IP

文章目录 一、需求说明二、配置步骤1、临时显示操作时间2、永久设置 三、补充说明1、HISTFILESIZE和HISTSIZE2、显示命令执行用户3、格式化输出参数配置4、历史命令保存位置 一、需求说明 系统运维工作中我们有时候需要查看历史命令&#xff0c;可以通过history命令查看&#x…

cmd长ping记录日志和时间_ping命令结果中如何显示时间

展开全部 可以62616964757a686964616fe78988e69d8331333431373266通过批处理实现&#xff0c;在后面加上时间。 echo off d: for /l %%i in (1,1,%999999999%) do ( ping %1192.168.1.1 -n 1% && echo %% >>ping.txt date /t >>ping.txt time /t >>p…

Vue中如何动态显示时间?

1&#xff1a;先上效果图&#xff1a; 2&#xff1a;注意点&#xff1a; &#xff08;1&#xff09;created( ) 与 mounted( )的区别就是&#xff1a; created 在模板渲染成html前调用&#xff0c;即通常初始化某些属性值&#xff0c;然后再渲染成视图 mounted在…

QT学习 实时显示时间

今天完成一个实时显示时间的小demo 先上DJ先上DJ 先看一下效果 以两种形式显示当前具体时间 先附上代码&#xff0c;再总结一下核心代码 &#xff08;1&#xff09; myweather.ui文件 创建一个Label&#xff0c;ObjectName值为text&#xff1b;创建一个LCD Number&#xff…

安卓实时显示时间

安卓开发过程中&#xff0c;有时候会用到实时的显示当前时间的功能&#xff0c;比如&#xff1a;自定义的状态栏就需要实时的更新当前时间&#xff0c;看下面图就是自定义的状态栏实时的更新时间&#xff1a; 实时显示更新时间代码&#xff1a;TimeThread.java import android.…

Linux中history命令显示时间

项目场景&#xff1a; 编写Linux shell自动判卷脚本过程中&#xff0c;使用到history命令时&#xff0c;如何显示命令执行时间问题的解决。 问题描述 Linux中的history命令默认只会显示两列&#xff0c;序号和命令&#xff0c;无法显示时间&#xff0c;如下所示&#xff1a; …

使用LCD1602显示温度或切换显示时间

项目名称&#xff1a;测温过温报警系统及时钟系统 此系统主要由AT89C51、DS18B20温度模块、LCD1602、喇叭组成。大致的原理是DS18B20温度采集到的数据传送给AT89C51的P3.4&#xff0c;最后通过LCD1602显示当前的实时温度&#xff0c;根据中断按键判断显示时间还是温度。 复习使…

vue项目中动态显示时间

vue项目中动态显示时间 前言一、js源代码二、效果图1.修改2.html与style的修改3.修改后效果图 总结 前言 在vue项目中动态显示时间&#xff0c;并且按日期、时间、星期一列排列。 我们想要的是下图时间显示方法。 一、js源代码 声明变量 export default {data() {return {ti…

51单片机lcd1602显示时间日期

实验内容&#xff1a; 使用51单片机控制LCD1602液晶显示屏显示 时间/日期/星期/温度 信息&#xff0c;并可通过按键设置值。 仿真效果展示&#xff1a; proteus仿真图&#xff1a; 硬件测试图&#xff1a; 说明&#xff1a; 硬件测试按键使用左侧的四个独立按键 key…

计算机怎么在桌面显示时间,怎么设置使电脑即显示时间有显示日期

怎么设置使电脑即显示时间有显示日期以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 怎么设置使电脑即显示时间有显示日期 单击“开始→控制面板区域和语言选项”,在“区域选项”选项卡中单击“自定义”按钮打开…

1.Vue显示实时时间

实时显示时间&#xff0c;代码如下&#xff1a; <div id"app">{{date}}</div><script>var appnew Vue({el:"#app",data:{date:new Date()},mounted:function(){var _thisthis;this.timersetInterval(function(){_this.datenew Date();}…