es5 new Array methods

forEach

没有返回值

其作用与for循环十分接近, 但并不能替代 for循环. 因为, forEach接受一个函数做参数, 在forEach的函数中没有 break, continue, 且return 不会跳出父函数(因为其本身就是一个函数)

在forEach的函数中 return, 不会中断forEach的继续执行.

如有下列代码:

1
2
3
4
5
6
7
function allLt0(arr) {
for (var a = 0; a < arr.length; a++) {
if (arr[a] > 0) {
return false;
}
}
}

改造成forEach

1
2
3
4
5
6
7
function allLt0(arr) {
arr.forEach(function (item) {
if (item > 0) {
return false;
}
})
}

这就有点想当然了

所以其实 forEach 只适合”对数组所有元素执行方法, 且不需要判断中断”的情况

map

执行完毕后返回一个数组, 数组长度等于原数组的长度

思考以下代码:

1
2
3
4
5
var arr = Array(5);
var b = arr.map(function (item,i) {
console.log(item);
return item + i;
})

结果并没有 console.log 执行, 且 b 是一个长度为5的空数组

原因是map/forEach会跳过数组的空元素, 而 arr 的元素全是空

如下的arr ,则不会跳过

1
2
var arr = [undefined,undefined,undefined,undefined,undefined];
var arr = Array.apply(Array, Array(5));

所以”空元素” != undefined

这个问题需要注意下,比如:

1
2
3
4
5
6
7
var arr = [];
arr[9] = 'David';
var b = arr.map(function (item) {
console.log(item);
return {name: item}
});
b;

此时b只有一个有效值,就是b[9], 长度也为10.

every

every 的用途在于, 对数组中的每个元素执行函数,如果有一个执行后没返回true, 则终止并得到false; 否则返回 true

也就是every有返回值, 是个 boolean

返回falsy值会导致every 终止

使用 every 时,记得显式的返回 true或false, 因为如果没返回 true, 就会被当成 false, 然后得到最终 false 的结果

1
2
3
4
5
6
7
8
var arr = [3,4,5];
var allLte3 = arr.every(function (item) {
if (item < 3) {
return false
}
// return true;
});
allLte3; // false

如上, 被注释掉的语句,很多新手可能会忘了写, 结果得到错误的判断结果

some

some与every是相反的. 他对每个数组元素执行函数,如果有某一个执行后返回 true, 则终止, 并得到 true

所以他也是有返回值的, 返回 boolean

要记得, 返回 truly, 会导致 some 终止!

1
2
3
4
5
6
7
8
9
10
11
var arr = [
{id:1,age:11, name:'11',salary:11000},
{id:2,age:21, name:'21',salary:21000},
{id:3,age:31, name:'31',salary:31000},
{id:4,age:41, name:'41',salary:41000},
{id:5,age:40, name:'41',salary:41000},
]
var hasLt30 = arr.some(function (item) {
if (item.age > 31) return item;
})
hasLt30; // true

注意在代码中,我试图返回一个对象, 但 hasLt30 却还是个boolean. 所以some并不会取得你返回的那个值,只是判断它, 并得到 true或 false

filter

用于取出对数组元素执行函数后,返回 true 的元素,并组成一个新数组.

其有返回值,是个数组

filter 是个常用方法. 比如, 从一个员工对象数组中, 找出所有年龄大于 30 的(便于开除):

1
2
3
4
5
6
7
8
9
var arr = [
{age: 31, name:'L'},
{age: 24, name:'M'},
{age: 32, name:'N'},
];
var Lt30 = arr.filter(function (item,i) {
return item.age >= 30;
});
Lt30;

filter 无法中止

indexOf 与 lastIndexOf

这两个比较简单. 要注意他们有第二个参数,即 fromIndex, 合理使用可节约大量时间开销:

1
2
var array = [2, 9, 9];
array.indexOf(9, 2); // 2

这两个方法太简单了, 第一个参数不能接受函数, 所以, 没法实现获取”对象数组中有某个字段的对象的 index” 的需求

另外, 他们还是属于循环,所以不宜大量使用. 比如以下场景, 判断A数组中的所有元素是否都存在于B数组中:

1
2
3
4
5
var A = [1,2,3,4,5];
var B = [0,1,2,3,4,5,6,7,8];
A.forEach(function (a) {
var isIn = B.indexOf(a) > -1;
})

这是一个不好的示例, 会产生好多次循环.

所以不要看起来方便就上了, 效率还是必须得考虑的.

reduce 与 reduceRight

这两个是这几个”新”方法中最复杂的, 且能实现的功能也多种多样.

他们除了接收一个函数作为第一个参数外, 还接受一个初始值(任何类型)做第二个参数:

1
arr.reduce(function(accu,item,i,array), initvalue)

且他们的参数函数,多了一个参数.其他方法都是(item, index, array), reduce/reduceRight的参数是: (accumulator, item, index, array)

记住 accumulator 这个单词,他已经说明了reduce的意义

其参数函数返回的对象,回成为下一个 accumulator

最常见的用法是对数组中的元素进行累加(比较求和,求乘积)

但实际情况能产生出很多变化,比如数组的元素不是简单值,而是复杂object.

比如我要得出所有员工加起来的总年龄:

1
2
3
4
5
6
7
8
9
10
var arr = [
{age:11, name:'11'},
{age:21, name:'21'},
{age:31, name:'31'},
{age:41, name:'41'},
]
var total = arr.reduce(function (accu, item) {
return accu.age ? accu.age + item.age : accu + item.age;
});
total;

reduce本意是用来进行累加计算(凡是要对数组进行累加计算的,都可以用它),但有时会用在一些貌似和累加没关系的地方.如取得年龄最大的员工:

1
2
3
4
5
6
7
8
9
10
11
var arr = [
{age:11, name:'11',salary:11000},
{age:21, name:'21',salary:21000},
{age:31, name:'31',salary:31000},
{age:41, name:'41',salary:41000},
{age:40, name:'41',salary:41000},
]
var oldest = arr.reduce(function (accu, item) {
return accu.age > item.age ? accu : item;
});
oldest; // {age:41, name:'41',salary:41000}

最终只得到一个对象.

3, 转换对象数组为以id为key的对象

就拿上面的数组来说,为了便于提取到对应id的对象,我们希望将这个数组变成这样一个大对象:

1
2
3
4
{
1:{id:1,age:11, name:'11',salary:11000},
2:{id:2...}
}

这个可以用for循环做到, 示例代码:

1
2
3
4
5
var obj = {};
for (var a = 0; a < arr.length; a++) {
obj[arr[a].id] = arr[a];
}
obj;

多了一些额外的变量, 但用reduce来实现更简单:

1
2
3
4
5
6
7
8
9
10
11
12
var arr = [
{id:1,age:11, name:'11',salary:11000},
{id:2,age:21, name:'21',salary:21000},
{id:3,age:31, name:'31',salary:31000},
{id:4,age:41, name:'41',salary:41000},
{id:5,age:40, name:'41',salary:41000},
]
var trans = arr.reduce(function (accu, item) {
accu[item.id] = item;
return accu;
}, {});
trans;

要注意传给 .reduce 的第二个参数(初始累加值), 这里是一个空object. 且要注意在函数里每次都返回它