在之前,我们要处理数组中的每一项,或者筛选出符合条件的项,通常操作都是使用 for 循环,然后逐个按照对应条件进行判断。

但现在你无需这么麻烦了,因为ES5里增加了一些相应的方法,它们可以满足与数组相关的日常需求。来看看都有哪些方法:

迭代 - forEach

forEach 对数组的每一项执行一个方法,它的基本语法如下:

array.forEach(callback(item, index, array){
//do something
}, this)

参数解释:

  • callback:数组每项需执行的函数
    1. item:当前项
    2. index:索引值
    3. array:迭代的数组
  • this:可选,callback里面绑定的this

它的返回值是 undefined,即你不能用该方法来生成一个新数组。

首先,我们用它来打印一个数组:

var arr = [1, 3, 5];

arr.forEach(console.log);
// 1 0 [1, 3, 5]
// 3 1 [1, 3, 5]
// 5 2 [1, 3, 5]

再来对数组进行操作,比如数组每项加倍:

// 简单数组
var arr = [1, 3, 5];

var result = arr.forEach(function(item, index, array) {
array[index] = 2*item;
});

console.log(arr);
// [2, 6, 10]

// 复合数组
var arr1 = [{num: 1}, {num: 3}];

var result = arr1.forEach(function(item, index, array) {
item.num *= 2;
});

console.log(arr1);
// [{num: 2}, {num: 6}]

对于简单数组,因为数组的每项是基本数据类型,所以只能用 array[index] 来进行赋值。

需要注意的是,forEach 方法不能跳出循环,除非在函数内部抛出一个异常。

前面说到,forEach 方法的返回值是 undefined,所以你不能使用它来生成一个新数组。倘若你非要使用它来生成一个新数组的话,那么可以利用它的第二个参数:

var result = [];
var arr = [1, 3, 5];

arr.forEach(function(item, index, array) {
this.push(item * 2);
}, result);

console.log(arr, result);
// [1, 3, 5] [2, 6, 10]

其实,这只是一种折中的方法,要生成新数组,或许使用 map 更适合。

迭代 - map

该方法会创建一个新数组,这个数组的每项是经过 callback 处理过的。语法如下:

var new_array = arr.map(function callback(item, index, array) { 
// Return element for new_array
}[, this])

参数解释:

  • callback:数组每项需执行的函数
    1. item:当前项
    2. index:索引值
    3. array:迭代的数组
  • this:可选,callback里面绑定的this

它的返回值是一个经过callback处理过的新数组。用法如下:

var arr = [1, 3, 5];

var result = arr.map(function(item, index, array) {
return item * 2;
});

console.log(arr, result);
// [1, 3, 5] [2, 6, 10]

上面的代码中,result 就是我们新生成的数组。arr 还是那个 arr,map 并不会改变原有数组。

再来一个求绝对值的例子:

var numbers = [-1, 3, -5];
var result = numbers.map(Math.abs);

console.log(numbers, result);
// [-1, 3, -5] [1, 3, 5]

迭代 - filter

顾名思义,filter 用于从数组里筛选出符合条件的项,它的语法如下:

var new_array = arr.filter(callback[, thisArg])

参数如下:

  • callback:用来测试数组每项的函数。调用时使用参数 (element, index, array)。
    返回true表示保留该元素(通过测试),false则不保留。
  • thisArg: 可选。执行 callback 时的用于 this 的值

它的返回值是 数组里通过callback测试所有项的集合,该集合是一个数组。

比如,筛选60分以上的学生:

var pointList = [{name: 'user1', point: 80}, {name: 'user2', point: 57}, {name: 'user3', point: 72}];

var passList = pointList.filter(function(item, index, array) {
return item.point >= 60;
});

console.log(pointList, passList);
// [{name: 'user1', point: 80}, {name: 'user2', point: 57}, {name: 'user3', point: 72}]
// [{name: 'user1', point: 80}, {name: 'user3', point: 72}]

它也不会改变原有数组。

迭代 - every

every 方法检测数组里的所有项是否都满足指定函数定义的条件,它的语法如下:

arr.every(callback[, thisArg])

参数如下:

  • callback:用来测试数组每项的函数
  • thisArg:执行 callback 时使用的 this 值

它的返回值是 一个布尔值,取决于数组里是否所有项都满足指定函数定义的条件,如果是,则返回 true,否者返回 false。用法如下:

var pointList = [{name: 'user1', point: 80}, {name: 'user2', point: 57}, {name: 'user3', point: 72}];

var isAllPass = pointList.every(function(item, index, array) {
return item.point >= 60;
});

console.log(isAllPass);
// false

上面的代码,判断是否所有的学生都及格了。由于 “user2” 为 57分,所有 isAllPass 的值为 false

需要注意的是,该方法若遇到返回 false(不满足条件)的数组项,则立马退出循环。

迭代 - some

相对于 everysome 方法的“条件”则比较宽松。该方法检测数组里的是否存在某项满足指定函数定义的条件,它的语法如下:

arr.some(callback[, thisArg])

参数如下:

  • callback:用来测试数组每项的函数
  • thisArg:执行 callback 时使用的 this 值

它的返回值是 一个布尔值,取决于数组里是否存在某项满足指定函数定义的条件,如果没有一项满足,则返回 false,否者返回 true

以下代码检测是否存在不及格学生:

var pointList = [{name: 'user1', point: 80}, {name: 'user2', point: 57}, {name: 'user3', point: 72}];

var isHasFail = pointList.some(function(item, index, array) {
return item.point < 60;
});

console.log(isHasFail);
// true

需要注意的是,该方法若遇到返回 true(满足条件)的数组项,则立马退出循环。

查找 indexOf、lastIndexOf

倘若你希望在数组里查找是否存在某项,你可以使用 indexOf 方法,它返回指定内容在数组里索引,如果没有找到,则返回 -1。语法如下:

arr.indexOf(searchElement[, fromIndex = 0])

参数如下:

  • searchElement:要查找的项
  • fromIndex: 可选,表示开始查找的位置。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。如果该参数为负数,则查出位置为 数组长度 + 该负数。如果相关结果仍然为负数,则整个数组都将会被查询,从0开始。

用法如下:

[1, 3, 5, 7, 9].indexOf(8); // -1
[1, 3, 5, 7, 9].indexOf(3); // 1
[1, 3, 5, 7, 9].indexOf(5); // 2
[1, 3, 5, 7, 5, 9].indexOf(5, 3); // 4
[1, 3, 5, 7, 5, 9].indexOf(5, -3); // 4
[1, 3, 5, 7, 5, 9].indexOf(5, -20); // 2

lastIndexOf 方法返回指定内容在数组里最后的索引,如果不存在,则返回 -1。语法如下:

arr.lastIndexOf(searchElement[, fromIndex = arr.length - 1])
  • searchElement:查找项
  • fromIndex:可选,从此位置开始逆向查找,默认为 arr.length - 1

用法如下:

[1, 3, 5, 7, 9].lastIndexOf(8); // -1
[1, 3, 5, 7, 5, 9].lastIndexOf(5); // 4
[1, 3, 5, 7, 5, 9].lastIndexOf(5, 3); // 2
[1, 3, 5, 7, 5, 9].lastIndexOf(5, -5); // -1

累计 reduce、reduceRight

reduce 方法用于累计数组里的某个值。它的语法如下:

arr.reduce(callback[, initialValue])

参数如下:

  • callback:处理数组每项的函数
    1. accumulator:累加器累加回调的返回值,它是上一次调用回调时返回的累积值
    2. currentValue:当前处理的数组项
    3. currentIndex: 当前处理的数组项的索引
    4. array:被处理的数组
  • initialValue:可选,用作第一个调用 callback的第一个参数的值。

它的返回值是累计处理的结果。

求数组总和:

var pointList = [80, 57, 72];

var total = pointList.reduce(function(accumulator, item, index, array) {
console.log(accumulator, item);
return accumulator + item;
});

console.log(total); // 209
// 80 57
// 137 72

合并多个数组:

var arr = [[1, 3, 5], ['a', 'b', 'c'], ['I', 'Ⅱ', 'Ⅲ']];

var result = arr.reduce(function(accumulator, item, index, array) {
console.log(accumulator, item);
return accumulator.concat(item);
});

console.log(result); // [1, 3, 5, "a", "b", "c", "I", "Ⅱ", "Ⅲ"]
// [1, 3, 5] ["a", "b", "c"]
// [1, 3, 5, "a", "b", "c"] ["I", "Ⅱ", "Ⅲ"]

reduce 一样,reduceRight 方法也是做累计处理的,只不过从数组的最末项开始处理。

var arr = ['u', 'o', 'y'];

var result = arr.reduceRight(function(accumulator, item, index, array) {
console.log(accumulator, item);
return accumulator + item;
});

console.log(result); // you
// y o
// yo u