数组对象map,filter,reduce,some,every方法详解
0. 前言
最近在前端笔试上数组的这几个方法上栽了几个跟头,缘于对这几个方法没有深入的了解,只知道其常规用法,没有顾虑到一些方法使用上的细节,在这里做个总结,复习的同时做个记录,方便以后查阅。
以上所有的数组迭代方法都来自于 ECMAScript5 对数组新增的操作方法,而不是 ECMAScript 6 新定义的方法。
参考资料:
《Javascript高级程序设计》
MDN: https://developer.mozilla.org/zh-CN/
菜鸟教程:http://www.runoob.com/
1. map() 方法
1.1 map() 方法常规使用
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
数组执行完map() 方法后返回一个新的数组,原数组元素不会发生改变。
var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
console.log(array1)
// expected output: Array [1, 4, 9, 16]
map() 方法不会对空数组进行检测, 结果仍然返回一个空数组,console.log(‘123’) 不会被执行。
var array1 = [];
const map1 = array1.map(x => {console.log('123')});
console.log(map1);
// expected output: Array []
如果 map() 方法不对元素进行操作且不指定返回值的话,新数组每个元素会返回 undefined 值
var array1 = [1,2,3];
const map1 = array1.map((item, index, arr) => {console.log('123')});
// expected output:
// 123
// 123
// 123
console.log(map1);
// expected output: Array [ undefined, undefined, undefined ]
1.2 map() 方法中的参数说明
array.map(function(currentValue,index,arr)
,thisValue
)方法一共可以传入两个参数。
第一个参数为一个函数 function(currentValue, index,arr)
,该函数中又包含了三个参数:
currentValue:表示的是当前元素的值。必须值。
index:当前元素的索引(从0开始)。可选值。
arr:当前元素属于的数组对象。也就是执行 map 方法的原数组对象。可选值。
var array1 = [1,2,3];
const map1 = array1.map((item, index, arr) => {console.log(item +':'+ index +':'+ arr)});
// expected output:
//1:0:1,2,3
//2:1:1,2,3
//3:2:1,2,3
第二个参数 thisValue
为可选。对象作为该执行回调时使用,传递给函数,用作 “this” 的值。
如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。
var array1 = [1,2,3];
var obj = {
mykey : 1000
}
var mykey = 2000
const map1 = array1.map(x => x + this.mykey);
console.log(map1)// (3) [2001, 2002, 2003]
该参数对箭头函数无效,箭头函数没有 this 对象,所以无法改变 this 指向
const map1 = array1.map(x => x + this.mykey, obj);
console.log(map1) //(3) [2001, 2002, 2003]
使用普通函数的结果
var array1 = [1,2,3];
var obj = {
mykey : 1000
}
var mykey = 2000
const map1 = array1.map(function(x){
return x + this.mykey
},obj);
console.log(map1) //(3) [1001, 1002, 1003]
1.3 map() 方法陷阱题
const map1 = [1,2,3].map(parseInt)
console.log(map1)
// (3) [1, NaN, NaN]
该题与函数传入的参数有关,详解见 https://www.cnblogs.com/Candybunny/p/5627905.html
2. filter() 方法
2.1 常规用法
filter() 方法返回一个新的数组,新的数组包含所有在函数中结果为 true 的元素,原数组不会改变。
var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6); // 返回值为true的所有结果都会加入新数组
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
2.2 参数说明
array.filter(function(currentValue,index,arr)
, thisValue
)
filter 参数的用法与 map 方法一致,不再重复描述。
3. reduce() 方法
3.1 reduce 方法的定义与常规用法
reduce() 方法对数组中的每个元素执行一个由用户提供的 reducer 函数,将其结果汇总为单个返回值。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10
3.2 reduce 方法的参数说明
语法: array.reduce(function(accumulator, currentValue, currentIndex, arr)
, initialValue
)
reduce() 方法传入两个参数:
第一个参数为一个函数。必须值
- 第一个参数传入的函数有 4 个参数:
- 1.accumulator 必需。初始值, 或者计算结束后的返回值。
- 2.currentValue 必需。当前元素的值。
- 3.currentIndex 可选。当前元素的索引,元素索引从 1 开始!
- 4.arr 可选。当前元素所属的数组对象。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue, index) => {
console.log('执行了第'+index+'次,accumulator='+accumulator+' currentValue=',currentValue)
return 'a'
};
let ret = array1.reduce(reducer)// "a"
// index 索引从 1 开始
// Output:
// 执行了第1次,accumulator=1 currentValue= 2
// 执行了第2次,accumulator=a currentValue= 3
// 执行了第3次,accumulator=a currentValue= 4
由上述代码可知,数组遍历中每一次的accumulator的值,均为上一次遍历中返回的结果。而accumulator的初始的值已经被固定,是数组的第一个元素。而最终返回的结果也是最后一次遍历中返回的值。例如这里就是返回一个“a”。
如果数组只有一个元素,reducer 不会被执行,reduce 方法直接返回数组的第一个元素
const array1 = [1];
const reducer = (accumulator, currentValue, index) => {
console.log('执行了第'+index+'次,accumulator='+accumulator+'currentValue=',currentValue)
return 9
};
let ret = array1.reduce(reducer)
console.log(ret) // Output: 1
如果reduce函数中没有返回任何值,且数组的长度大于1,则返回undefined
const array1 = [1,2,3];
const reducer = (accumulator, currentValue, index) => {
console.log('gg')
};
let ret = array1.reduce(reducer)
console.log(ret) // Output: undefined
如果数组为空则直接报错,提示数组没有初始值(首元素),也就是无法为 accumulator 赋予初值。
const array1 = [];
const reducer = (accumulator, currentValue, index) => {
return 1
};
let ret = array1.reduce(reducer)
// Uncaught TypeError: Reduce of empty array with no initial value
快速求数组总和
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue, index) => {
console.log('acc='+accumulator+' cur='+currentValue)
return accumulator + currentValue
};
let ret = array1.reduce(reducer)
console.log(ret)
// acc=1 cur=2
// acc=3 cur=3
// acc=6 cur=4
// 10
第二个参数为一个初始值 initValue。可选值。
reduce 方法在有第二个参数 initValue 的情况下,此时传入的 initValue 就充当了原来数组中的首元素的作用,初始的 accumulator 值被赋予为 initValue, 而不是数组的首元素,如果此时数组为空,也不会报错,会直接返回 initValue 的值。同时数组的 index 序号从 0 开始,数组的第一个元素也参与 reduce 计算。迭代执行的总次数为数组的元素个数。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue, index) => {
console.log('acc='+accumulator+' cur='+currentValue+' index='+index)
return accumulator + currentValue
};
let ret = array1.reduce(reducer, 5)
console.log(ret)
// acc=5 cur=1 index=0
// acc=6 cur=2 index=1
// acc=8 cur=3 index=2
// acc=11 cur=4 index=3
// 15
3.3 reduce 方法的构造(自定义函数实现数组 reduce 方法)
自己封装的,可能写的不是很好,大概是这么个意思,相比于原来的 reduce 不同之处在于数组为空的时候不再报错,返回一个 null。
Array.prototype.myreduce = function(func, initValue){
if(!this[0]){
return null
}
let begin = 0
let accumulator = 0
if(initValue){
accumulator = initValue
} else {
accumulator = this[0]
begin = 1
}
for(let i = begin; i < this.length; i++){
accumulator = func(accumulator, this[i], i, this)
}
return accumulator
}
let reducer = (acc, cur)=>acc+cur
console.log([1,2,3,4].myreduce(reducer,5))
// Output: 15
4. some() 方法和 every() 方法
4.1 定义与常规用法
some() 和 every() 方法都不会对空数组进行检测。
some() 和 every() 方法不会改变原始数组。
它们的返回值都为 true 或者 false
every() 是对数组中每一项运行给定函数,如果该函数对每一项返回true, 则返回true。
some() 是对数组中每一项运行给定函数,如果该函数对任一项返回true, 则返回true。
[1,2,3,4,5].some(x=>x >= 5) // true
[1,2,3,4,5].every(x=>x >= 5) //false
4.2 参数说明
array.every(function(currentValue,index,arr)
,thisValue
)
array.some(function(currentValue,index,arr)
,thisValue
)
它们的参数描述和用法与 map() 方法一致, 具体可以参考 map() 方法, 这里不再重复描述。
5. forEach() 方法
5.1 定义与用法
forEach() 方法对数组的每个元素执行一次提供的函数。
var array1 = ['a', 'b', 'c'];
array1.forEach(function(element) {
console.log(element);
});
// expected output: "a"
// expected output: "b"
// expected output: "c"
forEach() 方法没有返回值,或者说返回值为 undefined
var array1 = [1, 2, 3];
var ret = array1.forEach( x => x*2 )
console.log(ret) // undefined
5.2 参数说明
array.forEach(function(currentValue, index, arr)
, thisValue
)
第一个参数 function(currentValue, index, arr)
: 传入一个函数,该函数有三个参数:
- 第一个函数参数: currentValue 为当前元素值
- 第二个函数参数:当前元素索引值,从0开始
- 第三个函数参数:原数组对象
第二个参数thisValue
:当执行回调函数时用作 this 的值(参考对象)。如果这个参数为空, “undefined” 会传递给 “this” 值