几种需要注意的数组方法
concat
arr.concat
创建一个新数组,其中包含来自于其他数组和其他项的值
arr.concat(arg1, arg2, ...)
接受任意数量的参数,包括数组或值
例子:
let arr = [1, 2];
alert( arr.concat([3, 4]) );//1,2,3,4
alert( arr.concat([3, 4], [5, 6]) );//1,2,3,4,5,6
alert( arr.concat([3, 4], 5, 6) );//1,2,3,4,5,6
通常,它只复制数组中的元素。其他对象,即使它们看起来像数组一样,但仍然会被作为一个整体添加:
let arr = [1, 2];
let arrayLike = {
0: "something",
length: 1
};
alert( arr.concat(arrayLike) ); // 1,2,[object Object]
但是,如果类似数组的对象具有 Symbol.isConcatSpreadable
属性,那么它就会被 concat
当作一个数组来处理:此对象中的元素将被添加:
let arr = [1, 2];
let arrayLike = {
0: "something",
1: "else",
[Symbol.isConcatSpreadable]: true,
length: 2
};
alert( arr.concat(arrayLike) ); // 1,2,something,else
遍历:forEach
arr.forEach
方法允许为数组的每个元素都运行一个函数。
arr.forEach(function(item, index, array) {
// ... do something with item
});
例子:
// 对每个元素调用 alert
["aa", "bb", "bb"].forEach(alert);
而这段代码更详细地介绍了它们在目标数组中的位置:
["aa", "bb", "cc"].forEach((item, index, array) => {
alert(`${item} is at index ${index} in ${array}`);
});
该函数的结果(如果它有返回)会被抛弃和忽略。
filter
let results = arr.filter(function(item, index, array) {
// 如果 true item 被 push 到 results,迭代继续
// 如果什么都没找到,则返回空数组
});
例子:
let users = [
{id: 1, name: "aa"},
{id: 2, name: "bb"},
{id: 3, name: "cc"}
];
// 返回前两个用户的数组
let someUsers = users.filter(item => item.id < 3);
alert(someUsers.length); // 2
sort(fn)
arr.sort
方法对数组进行 原位(in-place) 排序,更改元素的顺序。(译注:原位是指在此数组内,而非生成一个新数组。)
它还返回排序后的数组,但是返回值通常会被忽略,因为修改了 arr
本身。
let arr = [ 1, 2, 15 ];
// 该方法重新排列 arr 的内容
arr.sort();
alert( arr ); // 1, 15, 2
这些元素默认情况下被按字符串进行排序。
从字面上看,所有元素都被转换为字符串,然后进行比较。对于字符串,按照词典顺序进行排序,实际上应该是 "2" > "15"
。
要使用我们自己的排序顺序,我们需要提供一个函数作为 arr.sort()
的参数。
function compareNumber(a, b) {
if (a > b) return 1; // 如果第一个值比第二个值大
if (a == b) return 0; // 如果两个值相等
if (a < b) return -1; // 如果第一个值比第二个值小
}
let arr = [ 1, 2, 15 ];
arr.sort(compareNumber);
alert(arr); // 1, 2, 15
简化后:
let arr = [ 1, 2, 15 ];
arr.sort(function(a, b) { return a - b; });
alert(arr); // 1, 2, 15
使用箭头函数:
arr.sort( (a, b) => a - b );
对于许多字母,最好使用 str.localeCompare
方法正确地对字母进行排序:
let countries = ['Österreich', 'Andorra', 'Vietnam'];
alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich(错的)
alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam(对的!)
reduce/reduceRight
当我们需要遍历一个数组时 —— 我们可以使用 forEach
,for
或 for..of
。
当我们需要遍历并返回每个元素的数据时 —— 我们可以使用 map
。
arr.reduce
方法和 arr.reduceRight
方法和上面的种类差不多,但稍微复杂一点。它们用于根据数组计算单个值。
语法是:
let value = arr.reduce(function(accumulator, item, index, array) {
// ...
}, [initial]);
该函数一个接一个地应用于所有数组元素,并将其结果“搬运(carry on)”到下一个调用。
参数:
accumulator
—— 是上一个函数调用的结果,第一次等于initial
(如果提供了initial
的话)。item
—— 当前的数组元素。index
—— 当前索引。arr
—— 数组本身。
应用函数时,上一个函数调用的结果将作为第一个参数传递给下一个函数。
因此,第一个参数本质上是累加器,用于存储所有先前执行的组合结果。最后,它成为 reduce
的结果。
例子,我们通过一行代码得到一个数组的总和:
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
alert(result); // 15
传递给 reduce
的函数仅使用了 2 个参数,通常这就足够了。
以表格的形式表示,每一行代表的是对下一个数组元素的函数调用:
sum |
current |
result |
|
---|---|---|---|
第 1 次调用 | 0 |
1 |
1 |
第 2 次调用 | 1 |
2 |
3 |
第 3 次调用 | 3 |
3 |
6 |
第 4 次调用 | 6 |
4 |
10 |
第 5 次调用 | 10 |
5 |
15 |
在这里,我们可以清楚地看到上一个调用的结果如何成为下一个调用的第一个参数。
我们也可以省略初始值:
let arr = [1, 2, 3, 4, 5];
// 删除 reduce 的初始值(没有 0)
let result = arr.reduce((sum, current) => sum + current);
alert( result ); // 15
结果是一样的。这是因为如果没有初始值,那么 reduce
会将数组的第一个元素作为初始值,并从第二个元素开始迭代。
计算表与上面相同,只是去掉第一行。
但是这种使用需要非常小心。如果数组为空,那么在没有初始值的情况下调用 reduce
会导致错误。
例如:
let arr = [];
// Error: Reduce of empty array with no initial value
// 如果初始值存在,则 reduce 将为空 arr 返回它(即这个初始值)。
arr.reduce((sum, current) => sum + current);
所以建议始终指定初始值。
arr.reduceRight
和 arr.reduce
方法的功能一样,只是遍历为从右到左。