JavaScript 回顾(一)map() 与 forEach() 的区别

1. 关于 map() 与 forEach() 的区别

参考文章援引自 FCC The Differences Between forEach() and map() that Every Developer Should Know

探讨两者区别主要从以下几点展开:

  • Definitions 定义
  • The returning value 返回值
  • Ability to chain other methods 链式操作其他方法
  • Mutability 是否改变原数组
  • Performance Speed 执行效率
  • Final Thoughts 应用场景的思考
1.1 Definitions 定义
  • map() 方法的参数是一个函数,然后针对数组的每一个成员执行该函数,最后返回一个全新的数组,该数组由调用函数执行后的结果所填充。也就意味着,新数组的成员是原数组的新形象,新数组的长度与原数组相同。
const myAwesomeArray = [5, 4, 3, 2, 1]

myAwesomeArray.map(x => x * x)

// Output: [25, 16, 9, 4, 1]
  • forEach() 同样接收一个函数作为参数,且对每一个数组成员执行该函数。不过,它并不像 map() 那样会返回一个新数组,它的返回值是 undefined
const myAwesomeArray = [
  { id: 1, name: "john" },
  { id: 2, name: "Ali" },
  { id: 3, name: "Mass" },
]

myAwesomeArray.forEach(element => console.log(element.name))
// >>>>>>>>> Output : john
//                    Ali
//                    Mass
1.2 The returning value 返回值

返回值上面的定义已经提及了,map() 是返回一个新数组,forEach() 返回 undefined

const myAwesomeArray = [1, 2, 3, 4, 5]
myAwesomeArray.forEach(x => x * x)
//>>>>>>>>>>>>>return value: undefined

myAwesomeArray.map(x => x * x)
//>>>>>>>>>>>>>return value: [1, 4, 9, 16, 25]
1.3 Ability to chain other methods 链式操作其他方法

是否可以链式操作是基于返回值的,所以 map() 可以链式调用其他方法,forEach() 不可以。

const myAwesomeArray = [1, 2, 3, 4, 5]
myAwesomeArray.forEach(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>> Uncaught TypeError: Cannot read property 'reduce' of undefined
myAwesomeArray.map(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>> return value: 55
1.4 Mutability 是否改变原数组

这个才是重点,改变还是不改变原数组。

mutable object 可变对象的定义:该对象创建后其状态可以改变即为可变对象。

根据 MDN 文档的解释:

  • forEach() 不会改变数组对象(但回调函数会改变数组)
  • map() 不会改变数组对象(尽管如此,回调函数如果有援引,可能会改变原数组)

感觉等于没说,难道是没有区别吗???
不,当然有。区别就在于 map() 方法返回一个全新的数组,这个新数组是由原数组变形衍生来的;而 forEach() 返回的是 undefined,所以是对原数组进行了改变操作。

结论:map() 调用回调函数也不会改变原数组,forEach() 如果调用了回调函数会改变原数组。

1.5 Performance Speed 执行效率

执行效率上有细微差别。可执行以下代码查看:

const myAwesomeArray = [1, 2, 3, 4, 5]

const startForEach = performance.now()
myAwesomeArray.forEach(x => (x + x) * 10000000000)
const endForEach = performance.now()
console.log(`Speed [forEach]: ${endForEach - startForEach} miliseconds`)

const startMap = performance.now()
myAwesomeArray.map(x => (x + x) * 10000000000)
const endMap = performance.now()
console.log(`Speed [map]: ${endMap - startMap} miliseconds`)

以我的电脑为例:

Speed [forEach]: 0.02500001573935151 miliseconds
Speed [map]: 0.01999997766688466 miliseconds
1.6 Final Thoughts 应用场景的思考
  • 如果是考虑修改或使用数据,可以使用 map(),因为会返回一个新的数组
  • 不使用数据的情况,推荐 forEach()

2. All methods 所有数组实例方法

有时候面试会被问到,有哪些数组实例的方法会改变原数组,哪些不会。数组 prototype 的所有方法如下:

console 输入 Array.prototype

2.1 改变原数组的方法
方法名 功能 返回值
unshift 首部添加 新数组长度
push 尾部添加 新数组长度
shift 首部删除 被删除元素
pop 尾部删除 被删除元素,空数组返回 undefined
splice(i, c, [n, m]) 通过删除或替换现有元素,或者原地添加新的元素来修改数组 被删除元素组成的数组
sort 用原地算法对数组的元素进行排序,默认 Unicode 位点进行排序 排序后的数组
reverse 将数组中元素的位置颠倒 颠倒后的数组
forEach 对数组的每个元素执行一次提供的函数 undefined
copyWithin(target[, start[, end]]) 浅复制数组的一部分到同一数组中的另一个位置 改变后的数组
fill(val, [start, end)) 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。 修改后的数组
includes 判断一个数组是否包含一个指定的值 包含则返回 true,否则返回 false
2.2 不改变原数组的方法
方法名 功能 返回值
concat 用于合并两个或多个数组 返回新数组
entries 返回一个新的Array Iterator对象 该对象包含数组中每个索引的键/值对,需要使用 iterableObj.next().value
keys 返回一个新的 Array Iterator对象 该对象包含数组中每个索引键
values 返回一个新的 Array Iterator对象 该对象包含数组中每个索引的值
every 测试一个数组内的所有元素是否都能通过某个指定函数的测试 布尔值
filter 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素 一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组
find 查找满足条件的第一个元素 返回元素的值,若无返回 undefined
findIndex 查找满足条件的第一个元素 返回元素的索引,若无返回 -1
flat(depth) 扁平化嵌套数组或移除数组空项 一个包含将数组与子数组中所有元素的新数组
flatMap arr.map(callback).flat(1) 几乎相同 一个新的数组,其中每个元素都是回调函数的结果,并且depth 值为1
indexOf(searchE, fromIndex) findIndex 多一个参数,也是查找元素 返回元素的索引,若无返回 -1
lastIndexOf 最后一个索引 返回元素的索引,若无返回 -1
join(separator) 将一个数组或一个类数组对象的所有元素连接成一个字符串 返回拼接的字符串
map 创建一个符合回调函数的数组 回调函数的结果
slice([begin, end)) 一个由 begin 和 end 决定的原数组的浅拷贝 一个含有被提取元素的新数组

3. 其他举例

例(1)模糊查询,String 的 includes 结合 Array 的 filter 示例:

var strs = ["back", "to", "basics"];
console.log(strs.filter(str => str.includes("a"))); // ["back", "basics"]

例(2)如下 JavaScript 代码运行后,b、c 的值分别是?

var a = ["monkey", "elephant", "horse"];
var b = a;
var c = a.slice();
a.push("panda");

答案:

b = ["monkey", "elephant", "horse", "panda"];
c = ["monkey", "elephant", "horse"];

a、b 指向同一个引用地址,c 的指向是 slice 创建的新数组。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 webpack介绍和使用 一、webpack介绍 1、由来 ...
    it筱竹阅读 11,089评论 0 21
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,682评论 7 110
  • 记得2004年的时候,互联网开发就是做网页,那时也没有前端和后端的区分,有时一个网站就是一些纯静态的html,通过...
    阳阳阳一堆阳阅读 3,278评论 0 5
  • webpack使用学习 本分享学习借鉴webpack中文官网,官网链接(中文文档):https://www.web...
    腿毛怪丶叔叔阅读 875评论 0 5
  • 轰隆轰隆雷声响, 在山的南边, 请再等一等, 牧童在拾笛; 轰隆轰隆雷声响, 在山顶, 请再等一等, 农夫在拾锄;...
    水曦蕊阅读 117评论 2 1