JavaScript数组常用方法详解
本文由 小茗同学 发表于 2016-08-17 浏览(3307)
最后修改 2021-12-08 标签:javascript 数组 常用 方法 详解 array

前言

JavaScript中的数组有很多实用方法,但是方法多了难免记不住,本文就是对一些常用方法做一个基本的梳理。

为方便对比和理解,这里统一假设有一个名为a的数组:var a=[4,6,1,7,2,9,3,6],以下所有方法的测试都是基于这个数组。

兼容性较好的

会修改原数组的方法:pushpopshiftunshiftreversesortsplice

push(value)

进栈,亦即从最后面追加元素:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.push(8));//返回数组的最新长度:9
console.log(a);//输出:[4, 6, 1, 7, 2, 9, 3, 6, 8]

pop()

出栈,亦即删除最后一个元素:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.pop());//返回出栈的内容:6
console.log(a);//输出:[4, 6, 1, 7, 2, 9, 3]

shift()

删除第一个元素,如果没有了返回undefined,刚好与pop方向相反:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.shift());//返回第一个元素:4
console.log(a);//输出:[6, 1, 7, 2, 9, 3]

unshift(value)

从第一个元素开始插入元素(可以是多个),刚好与push方向相反:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.unshift(8));//返回数组的最新长度:9
console.log(a);//输出:[8, 6, 1, 7, 2, 9, 3]

reverse()

反转数组,影响原数组:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.reverse());//返回最新数组
console.log(a);//输出:[6, 3, 9, 2, 7, 1, 6, 4]

sort(orderfunction)

数组排序(默认按字符串升序排序),影响原数组:

var a = [5,7,8,7,4,37,88,1,2,53,5,12];
console.log(a.sort()); // 返回最新数组
// 可以看出,默认排序是把它当成字符串来排序了
console.log(a); // 输出:[1, 12, 2, 37, 4, 5, 5, 53, 7, 7, 8, 88]

自定义排序:

var a = [5,7,8,7,4,37,88,1,2,53,5,12];
// 数组升序排序
a.sort((a, b) => a < b ? -1 : (a > b ? 1 : 0));
console.log(a); // 输出:[1, 2, 4, 5, 5, 7, 7, 8, 12, 37, 53, 88]
var array = [{name:'lxa', age:24}, {name:'xmy', age:27}, {name:'hm', age:23}];
array.sort(function(a, b)
{
	return a.age < b.age ? 1 : (a.age > b.age ? -1 : 0);
});

以上方法中切记不要忘了a==b时返回 0,而不能简单的写return a < b ? -1 : 1;,否则你就是给你的代码埋了一个隐藏炸弹,这个炸弹很难找的!

join(separator)

将数组用某个字符拼接成字符串,默认英文逗号“,”:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.join('_'));//返回:4_6_1_7_2_9_3_6
console.log(a);//输出:[4, 6, 1, 7, 2, 9, 3, 6]

concat

concat(arr1[, arr2, arr3...])用于合并2个或者多个数组,原数组不会变化:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.concat([11, 12, 13])); // [4, 6, 1, 7, 2, 9, 3, 6, 11, 12, 13]
console.log(a.concat([11, 12, 13], [14, 15])); // [4, 6, 1, 7, 2, 9, 3, 6, 11, 12, 13, 14, 15]
console.log(a.concat(11, [12, 13, 14])); // [4, 6, 1, 7, 2, 9, 3, 6, 11, 12, 13, 14]

slice(start, end)

返回从原数组中指定开始下标到结束下标之间的项组成的新数组,注意原始数组不会变,同时注意下标:start <= i < end,end如果不传则默认为数组的长度:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
console.log(a.slice(2, 5));//返回2-4位:[1, 7, 2]
console.log(a);//a保持不变,输出:[4, 6, 1, 7, 2, 9, 3, 6]
console.log(a.slice(2)); // 输出:[1, 7, 2, 9, 3, 6]

这个方法和string.substring(start, end)非常类似,都是截取的意思。

console.log(['a','b','c','d'].slice(1,3)); // 输出['b', 'c']
console.log('abcd'.substring(1,3)); 输出 'bc'

关于substring和substr

这里插播一条关于substring和substr的知识点,因为内容太少,就不单独写一篇文章了。

关于substring和substr的区别,前者是string.substring(start, end),后者是substr(start, count)

对于substring:

  • start <= idx < end ;
  • 如果start或者end为负数,强制当成0处理;
  • 如果start比end小,交换二者;

所以:

'abcdefg'.substring(2, 4); // cd
'abcdefg'.substring(2, -4); // ab,相当于是substring(2, 0),又由于2比0大,所以又相当于substring(0, 2)
'abcdefg'.substring(-2, 4); // abcd
'abcdefg'.substring(-2, -4); // ''

对于substr:

  • start如果为负数,则倒着数,也就是(length+start),如果(length+start)还为负数,则看做0处理;
  • count如果为负数,当做0处理;
  • 如果count太大内容不够,则一直到结尾即停止,不会重新回到开始继续截取,也就是返回的结果长度可能比count小;

所以:

'abcdefg'.substr(2, 4); // cdef
'abcdefg'.substr(2, -4); // ''
'abcdefg'.substr(-2, 4); // fg,其实相当于 substr(7-2, 4);
'abcdefg'.substr(-2, -4); // ''
'abcdefg'.substr(-12, 4); // 'abcd',由于(7-12)仍然为负数,所以看做0,即相当于:substr(0, 4)

之所以搞这么仔细,是因为昨天面试的时候碰到这个题目没有答上来,囧(o(╯□╰)o)

splice(start, deleteCount, val1, val2, …)

这个方法功能有点强大,也有点复杂。从start位置开始删除deleteCount项(deleteCount不传则默认删除后面全部),并从该位置起插入val1,val2,... ,影响原数组,返回被删除的项。可以把这个方法和string.substr(start, count)对比,只不过splice更高级,删除之后还可以追加内容。

使用splice可以实现以下全部方法(以下==表示等价):

  • array.splice(0, 1) == array.shift()
  • array.splice(0, 0, num) == array.unshift(num)
  • array.splice(a.length-1, 1) == array.pop()
  • array.splice(a.length, 0, num) == array.push(num)
var a = [1,2,3,4,5];
var b = a.splice(2,2,7,8,9); // 从索引为2开始删除2个元素(这里是3和4),然后再插入7,8,9
console.log(a, b); //a:[1,2,7,8,9,5], b:[3,4]

var b = a.splice(0,1); //同shift
a.splice(0,0,-2); var b = a.length; //同unshift
var b = a.splice(a.length-1,1); //同pop
a.splice(a.length,0,6,7); //同push

较新的方法

forEach

forEach用来遍历一个数组,它是ES5中新增的,相对于for循环,使用它会更简单,但是它无法中途跳出循环,这是最大的缺点。它的回调函数接收2个参数:(value, index)

var a = [4, 6, 1, 7, 2, 9, 3, 6];
a.forEach((value, index) => console.log(value, index));

map

map()方法用于创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果,map不会修改原数组。

var a = [4, 6, 1, 7, 2, 9, 3, 6];
var b = a.map(value => value* 2);
console.log(a); // a没有变化
console.log(b); // [8, 12, 2, 14, 4, 18, 6, 12]

filter

filter()用于过滤一个数组,返回true就保留,否则丢弃,不会修改原数组:

var a = [4, 6, 1, 7, 2, 9, 3, 6];
var b = a.filter((value) => value < 6); // 只返回小于6的元素
console.log(a); // a没有变化
console.log(b); // [4, 1, 2, 3]

some

some()方法用于判断数组中是否有元素满足某个条件,只要有一个满足就返回true

var a = [4, 6, 1, 7, 2, 9, 3, 6];
a.some((value) => value > 9); // 判断数组a中是否有大于9的元素,返回false
a.some((value) => value > 6); // 判断数组a中是否有大于6的元素,返回true

every

every()方法和some刚好相反,用于判断数组中是否所有元素都满足某个条件,只要有一个不满足就返回false

var a = [4, 6, 1, 7, 2, 9, 3, 6];
a.every(value => value > 0); // 判断数组a中是否所有元素都大于0,返回true
a.every(value => value > 2); // 判断数组a中是否所有元素都大于2,返回false

reduce

reduce()方法接收一个函数作为累加器,每次将上次返回的值与当前值进行运算,最终返回最后的值。

语法:array.reduce((sum, current, idx) => some + current, initValue),最后的initValue是可选的。

[2,4,3,5].reduce((sum, current, idx) => {
	console.log(sum, current, idx);
	return sum + current;
});

输出:

2 4 1
6 3 2
9 5 3
14

可以看到,当没有传initValue时,是从数组第二个参数开始遍历的,第一个参数直接当成第一次循环的sum了,这也符合我们的预期,所以,可以猜测,当数组长度<=1时是不会执行回调函数的,事实确实如此,长度等于1时直接返回第0个内容,长度等于0时直接报错。

但是如果传了initValue呢,会从数组第一个参数开始遍历:

[2,4,3,5].reduce((sum, current, idx) => {
	console.log(sum, current, idx);
	return sum + current;
}, 100);

输出结果:

100 2 0
102 4 1
106 3 2
109 5 3
114

其实,下面2种写法是完全一致的,没有任何区别:

[2,4,3,5].reduce((sum, current) => sum + current, 100);
[100,2,4,3,5].reduce((sum, current) => sum + current);

自行封装常用方法

findRepeat

查找2个数组中重复的数组

function findRepeat(arr1, arr2) {
	return arr1.filter(item => arr2.some(it => item === it));
}
// test
findRepeat([1,2,3,4], [3,4,5,6]); // [3,4]

findAdd

查找数组2相比数组1新增的项:

function findAdd(arr1, arr2) {
	return arr2.filter(item => !arr1.some(it => item === it));
}
// test
findAdd([1,2,3,4], [3,4,5,6]); // [5,6]

findRemove

查找数组2相比数组1删除的项:

function findRemove(arr1, arr2) {
	return arr1.filter(item => !arr2.some(it => item === it));
}
// test
findRemove([1,2,3,4], [3,4,5,6]); // [1,2]