JavaScript 回顾(一)map() 与 forEach(

2019-05-12  本文已影响0人  MercuryWang

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

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

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

1.1 Definitions 定义
const myAwesomeArray = [5, 4, 3, 2, 1]

myAwesomeArray.map(x => x * x)

// Output: [25, 16, 9, 4, 1]
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 文档的解释:

感觉等于没说,难道是没有区别吗???
不,当然有。区别就在于 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 应用场景的思考

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 创建的新数组。

上一篇下一篇

猜你喜欢

热点阅读