目录
数组遍历方法总结
1.forEach
方法对数组的每个元素执行一次给定的函数
用法:依次向 callback 函数传入三个参数:数组当前值,数组当前项的索引,数组对象
arr.forEach(callback(currentValue [, index [, array]]))
需要注意的是
- forEach()在被调用时不会改变原数组,尽管 callback 函数在被调用时可能会改变原数组
- forEach()总是返回undefined,而且不可链式调用
- 不对未初始化的值进行任何操作(稀疏数组),直接跳过callback函数
let items = [1, 2,, 4]
let num = 0
let temp = items.forEach(ele => {
console.log(ele)
num++
})
console.log("num: " + num)
console.log("temp: " + temp)
// 1
// 2
// 4
// num: 3 跳过了未初始化的值,只执行了3次
// temp:undefined
2.map
方法创建一个新数组,其结果是该数组中的每个元素都调用一次提供的函数后的返回值
用法:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
})
注意点:
- map在被调用时不会改变原数组,会生成一个新数组返回
- 从来没被赋过值不会被调用callback
- 当callback没有返回值时,新数组也会保留该项,值为undefined
- 当遇到稀疏数组是,map()会跳过空位,但会保留这个值
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9]
var items= [1, 2,, 4,];
var filteredNumbers = items.map(function(num, index) {
if(index < 3) {
return num;
}
});
console.log(filteredNumbers) // [1, 2, , undefined]
有个很容易犯的错误,例如:
["1", "2", "3"].map(parseInt);
期望输出[1, 2, 3] 实际结果是[1, NaN, NaN]
在这里parseInt作为回调函数实际上接收了currentValue,index两个参数
// parseInt(string, radix) -> map(parseInt(value, index))
/* 第一次 (index is 0): */ parseInt("1", 0); // 1 当radix参数为0,parseInt() 会根据十进制
/* 第二次 (index is 1): */ parseInt("2", 1); // NaN 当radix该参数小于 2 或者大于 36 返回NaN
/* 第三次 (index is 2): */ parseInt("3", 2); // NaN 用2进制来解析,应以 0 和 1 开头,所以结果为 NaN
// 解决办法:
function returnInt(element) {
return parseInt(element, 10);
}
['1', '2', '3'].map(returnInt); // [1, 2, 3]
// 还可以用更简单的方法避免陷阱:
['1', '2', '3'].map(Number); // [1, 2, 3]
3.for...of / for...in
for...of在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
for...in 以任意顺序遍历一个对象的除Symbol以外的可枚举属性
for...of 与for...in的区别
- for...in迭代的顺序不一定按照次序,如果当迭代访问顺序很重要的数组时,最好用整数索引去进行for循环、forEach、for...of
- for..in 会返回所有可枚举属性,包括原型链上的属性
- for...in循环出的是key,for...of循环出的是value
// for...in 语句以任意顺序迭代对象的可枚举属性。
// for...of 语句遍历可迭代对象定义要迭代的数据。
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for (let i in iterable) {
console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // 0, 1, 2, "foo"
}
}
for (let i of iterable) {
console.log(i); // 3, 5, 7
}
4.some
方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值
注意点:
- some不会改变原数组
- 空数组调用任何情况都是返回false
- 当遇到稀疏数组是,map()会跳过空位不执行回调函数
- some遍历的数组长度第一次执行回调时已经确定,所以在callback中添加进数组的值不会被callback访问到,已经被删除的值不会被访问到
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
// 使用箭头函数更简洁的写法
[2, 5, 8, 1, 4].some(x => x > 10); // false
[12, 5, 8, 1, 4].some(x => x > 10); // true
// 空数组
[].some(x => x < 10) // false
//第一次执行回调已经确定元素的范围,新增的不会被访问到
let item = [1, 2, 5]
let isBiggerThan = item.some(x => {
item.push(20)
return x > 10
})
console.log(item) // [1, 2, 5, 20, 20, 20]
console.log(isBiggerThan) // false
// 已经被删除的元素也不会被访问到
var item = [1, 2, 15]
let isBiggerThan = item.some(x => {
item.pop() // 删除最后一项元素
return x > 10
})
console.log(item) // [1]
console.log(isBiggerThan) // false
5.every
方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。返回一个布尔值。
注意点:
- every不会改变原数组
- 遇到稀疏数组,回调函数会直接跳过空位
- 同some一样,遍历的数组长度第一次执行回调时已经确定,在callback中添加进数组的值不会被callback访问到,已经被删除的值不会被访问到
- 空数组调用任何情况都是返回true
// 空数组
[].every(x => x < 10) // true
// 稀疏数组,跳过未赋值的值
[13,,20].every(x => x > 10) // true
6.filter
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
注意点:
- filter不会改变原数组,只返回过滤后的新数组
- callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用
- 同some、every一样,遍历的数组长度第一次执行回调时已经确定,在callback中添加进数组的值不会被callback访问到,已经被删除的值不会被访问到
function isBigEnough(element) {
return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
7.find
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined
注意点:
- find方法不会改变原数组
- 当稀疏数组调用find方法时,回调函数不会跳过没有值的索引,这说明find方法效率要低于那些只遍历有值索引的方法
- 第一次调用就确定索引范围,添加到数组的新元素将不会被callback访问到,被删除的值仍会被访问到(undefined)
// 稀疏数组,不会跳过
let num = 0;
let hasRight [1,2,3,,5].find(x => {
console.log(num) // 0 1 2 3 4
num++
return x > 5
})
console.log(hasRight) // undefined
8.findIndex
方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。
注意点:
- findIndex不会改变原数组
- 不会跳过稀疏数值中未初始化值的索引
- 第一次调用就确定索引范围,添加到数组的新元素将不会被callback访问到,被删除的值仍会被访问到
const array1 = [5, 12, 8, 130, 44];
const isLargeNumber = array1.findIndex(element => element > 13); // 3
9.reduce
方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
用法:reduce接受两个参数,分别是callback(reducer)、初始值initialValue(可选)
- reducer接受4个参数,分别是Accumulator累计器、CurrentValue 当前值、CurrentIndex 当前索引、SourceArray 原数组
- initialValue,作为第一次调用 callback函数时的第一个参数的值,如果不传默认值为数组的第一个元素
注意点:
- reduce不会改变原数组
- reduce会跳过稀疏数值中未初始化值的索引
- 如果数组为空,且没有提供初始值,会抛出TypeError
- 如果数组只有一个元素,且没有初始值,或者提供了初始值但数组为空,reduce不执行回调直接返回唯一值
- 如果没有提供初始值,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供初始值,从索引0开始。
- 如要累加对象数组的属性,必须提供初始值
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr ); // 10
// 提供初始值
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue;
}, 10 ); // 20
// 箭头函数
[ 0, 1, 2, 3 ].reduce(
( acc, cur ) => acc + cur,
0
);
// 空数组
[].reduce((prev, curr) => prev + curr ); // TypeError
// 提供了初始值
[].reduce((prev, curr) => prev + curr, 20 ); // 20
// 数组长度为1
[15].reduce((prev, curr) => prev + curr ); // 15
//累加对象数组
var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
return accumulator + currentValue.x;
},initialValue)
console.log(sum) // 6
// 无初始值,得到不是期望的返回
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
return accumulator + currentValue.x;
})
console.log(sum) // "[object Object]23"
10.总结
forEach | map | for...of | for...in | some | every | filter | find | findIndex | reduce | |
---|---|---|---|---|---|---|---|---|---|---|
是否改变原数组 | × | × | × | × | × | × | × | × | × | × |
是否有返回值 | × | √ | × | × | √ | √ | √ | √ | √ | √ |
返回值类型 | × | Array | × | × | Boolean | Boolean | Array | value/undefined | index/-1 | 累加的值 |
稀疏数组 | 跳过 | 跳过,保留空位 | 正常遍历 | 跳过 | 跳过 | 跳过 | 跳过 | 正常遍历 | 正常遍历 | 正常遍历 |