START
- 朋友遇到面试题,问到
foreach
和Map
的区别。 - 想到遍历数组,肯定是我们CV工程师经常用到的地方,但是方法有点多,很容易混淆,那不就踩坑了嘛。
- 今天呢,就好好研究,以及复习一下,JS中数组的遍历。
一.普通for循环
- 使用方式
var arr = [1, 2, 3, 4, 5, 6];
for (var i = 0; i < arr.length; i++) {
console.log("索引:" + i + " 值:" + arr[i]);
}
- 输出
索引:0值:1
索引:1值:2
索引:2值:3
索引:3值:4
索引:4值:5
索引:5值:6
- 总结
- 比较直观,简单明了。
- 略微比较麻烦,需要敲蛮久。
- 其他
- 这里多提一句,上述示例的代码使用的是
var
声明的变量i
,由于var
声明的变量没有块级作用域(ES5只有函数中才有块级作用域),在一些特殊的情况下会出问题,推荐使用ES6中的let
去声明变量i
. - 如果想详细了解,这一块的,推荐一个博客:深入理解js_for循环条件中使用var为什么会出问题?(js块级作用域理解)
- 这里多提一句,上述示例的代码使用的是
二.forEach
- 官方说明文档
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
-
官方用法
arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
参数说明: callback 为数组中每个元素执行的函数,该函数接收一至三个参数: currentValue 数组中正在处理的当前元素。 index 可选 数组中正在处理的当前元素的索引。 array 可选 forEach() 方法正在操作的数组。 thisArg 可选 可选参数。当执行回调函数 callback 时,用作 this 的值。
举例使用方式(这里就不举例使用thisArg参数了,以常用的作为示例)
let arr = ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"];
let out = arr.forEach((element, index,array,) => {
console.log("element:" + element + " index:" + index + " array:" + array );
});
console.log("看一看foreach方法有没有返回值:",out)
- 输出
element:q index:0 array:q,w,e,r,t,y,u,i,o,p
element:w index:1 array:q,w,e,r,t,y,u,i,o,p
element:e index:2 array:q,w,e,r,t,y,u,i,o,p
element:r index:3 array:q,w,e,r,t,y,u,i,o,p
element:t index:4 array:q,w,e,r,t,y,u,i,o,p
element:y index:5 array:q,w,e,r,t,y,u,i,o,p
element:u index:6 array:q,w,e,r,t,y,u,i,o,p
element:i index:7 array:q,w,e,r,t,y,u,i,o,p
element:o index:8 array:q,w,e,r,t,y,u,i,o,p
element:p index:9 array:q,w,e,r,t,y,u,i,o,p
看一看foreach方法有没有返回值: undefined
-
个人总结
- forEach肯定是经常会被使用的,第一个参数是元素,第二个参数是索引,第三个参数是被遍历的数组本身。这个不要记混淆了。其次,有时候不需要索引,数组,参数是可以省略的。
- 可以看到forEach是没有返回值的。打印出来是undefined。
-
官方文档总结的注意事项!!!
-
forEach()
方法按升序为数组中含有效值的每一项执行一次callback
函数,那些已删除或者未初始化的项将被跳过 。
个人理解就是,从数组索引由小到大,开始遍历。如果存在没有项,或者被删除了,将会跳过。
下面的例子,就包含了,1.存在没有项;2.元素被删除了。
let arr = ["q", "w", "e", "r", , , "u", "i", "o", "p"]; let out = arr.forEach((element, index, array) => { console.log("element:" + element + " index:" + index + " array:" + array); if (element === "i") { // shift(); 移除数组第一个元素,这里移除的是`i`后面的`o` arr.shift(); } }); console.log("看一看foreach方法有没有返回值:", out); // 打印 element:q index:0 array:q,w,e,r,,,u,i,o,p element:w index:1 array:q,w,e,r,,,u,i,o,p element:e index:2 array:q,w,e,r,,,u,i,o,p element:r index:3 array:q,w,e,r,,,u,i,o,p element:u index:6 array:q,w,e,r,,,u,i,o,p element:i index:7 array:q,w,e,r,,,u,i,o,p element:p index:8 array:w,e,r,,,u,i,o,p 看一看foreach方法有没有返回值: undefined
-
forEach()
遍历的范围在第一次调用callback
前就会确定。调用forEach
后添加到数组中的项不会被callback
访问到。
-
下列代码可以看到,元素是添加进去了,但是并没有被遍历
let arr = ["q", "w", "e", "r"]; let out = arr.forEach((element, index, array) => { console.log("element:" + element + " index:" + index + " array:" + array); arr.push("新增的元素" + index); }); console.log("看一看foreach方法有没有返回值:", out); // 打印 element:q index:0 array:q,w,e,r element:w index:1 array:q,w,e,r,新增的元素0 element:e index:2 array:q,w,e,r,新增的元素0,新增的元素1 element:r index:3 array:q,w,e,r,新增的元素0,新增的元素1,新增的元素2 看一看foreach方法有没有返回值: undefined
-
forEach()
总是返回undefined
值,并且不可链式调用 .
上述代码已经打印了返回值,是undefined。
- 即
forEach
不会直接改变调用它的对象,但是那个对象可能会被callback
函数改变。
个人理解就是,forEach默认不会直接修改原数组,但是呢,也可以在方法中对原数组进行修改。
- 除了抛出异常以外,没有办法中止或跳出
forEach()
循环。如果你需要中止或跳出循环,forEach()
方法不是应当使用的工具。 - 如果使用 promise 或 async 函数作为
forEach()
等类似方法的callback
参数,最好对造成的执行顺序影响多加考虑,否则容易出现错误。
三.Map()函数
- 官方说明文档
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map
-
功能说明
map()
方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。 官方用法
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
- 举例使用方法
let arr = [1, 2, 3, 4];
let newArr = arr.map(function (element, index) {
return element + 4;
});
console.log("原本的数组:",arr,"新返回的数组",newArr)
原本的数组: [ 1, 2, 3, 4 ] 新返回的数组 [ 5, 6, 7, 8 ]
-
个人总结
对于map我个人的理解,就是保持原本数组不变,按照你的需求,处理一遍数组里面的元素,并返回给你你处理过后的数组。
A/你不打算使用返回的新数组(或/且) B/ 你没有从回调函数中返回值 ,不要推荐使用map,去使用其他的方法。
四.filter()函数
-
官方文档
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
功能说明
filter()
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
-
使用示例
let arr = [1, 2, 3, 4]; let newArr = arr.filter((element) => { return element>2 }); console.log("原本的数组:",arr,"新返回的数组",newArr) //输出 原本的数组: [ 1, 2, 3, 4 ] 新返回的数组 [ 3, 4 ]
-
个人总结
- 本身
filter
英文就是过滤器的意思。使用它,去筛选出符合设定要求的数据, - 和map相同,不会修改原数组。不同的是它会返回满足筛选条件的元素,组成的一个新数组。
- 本身
五.some()函数
-
官方文档
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/some
功能说明
some()
方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。
-
使用示例
const array = [1, 2, 3, 4, 5]; // checks whether an element is even const even = (element) => element % 2 === 0; console.log(array.some(even)); // expected output: true
-
个人总结
- 不会修改原数组
- 只要数组中有一个元素满足条件,就会返回ture,经常用于,判断数组中是否有符合条件的数据。
- 返回值类型为,布尔值
六.every()函数
-
官方文档
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/every
功能说明
every()
方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。
-
使用示例
const isBelowThreshold = (currentValue) => currentValue < 40; const array1 = [1, 30, 39, 29, 10, 13]; console.log(array1.every(isBelowThreshold)); // expected output: true
-
个人总结
- 注意:若收到一个空数组,此方法在一切情况下都会返回
true
。 - 不会修改原数组
- 返回值类型为,布尔值
-
every
和数学中的"所有"类似,当所有的元素都符合条件才会返回true
。正因如此,若传入一个空数组,无论如何都会返回true
。(这种情况属于无条件正确:正因为一个空集合没有元素,所以它其中的所有元素都符合给定的条件。)
- 注意:若收到一个空数组,此方法在一切情况下都会返回
七.find()函数
-
官方文档
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/find
-
功能说明
find()
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined
。 -
使用示例
const array1 = [5, 12, 8, 130, 44]; const found = array1.find(element => element > 10); console.log(found); // expected output: 12
-
个人总结
不会修改原数组
返回值类型为: 元素的值或者
undefined
。
八.findIndex()函数
-
官方文档
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
功能说明
findIndex()
方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
-
使用示例
const array1 = [5, 12, 8, 130, 44]; const isLargeNumber = (element) => element > 13; console.log(array1.findIndex(isLargeNumber)); // expected output: 3
-
个人总结
- 不会修改原数组
- 返回值类型为: 元素的索引或者 -1
- 功能其实和find很类似,只是返回值一个是元素的值,一个是索引,还有就是没有找到的情况,一个返回的是undefined一个是-1
tips
说说forEach
和map
的区别
- 能用
forEach()
做到的,map()
同样可以。反过来也是如此。 -
map()
会分配内存空间存储新数组并返回,forEach()
不会返回数据。 -
forEach()
允许callback
更改原始数组的元素。map()
返回新的数组。
如何选择
-
forEach
适合于你并不打算改变数据的时候,而只是想用数据做一些事情 -- 比如存入数据库或则打印出来。 -
map()
适用于你要改变数据值的时候。不仅仅在于它更快,而且返回一个新的数组。这样的优点在于你可以使用复合(composition)(map(), filter(), reduce()等组合使用)来玩出更多的花样。
END
- 结束
2021/04/01