JavaScript数组常用方法解析和深层次js数组扁平化

前言

数组作为在开发中常用的集合,除了for循环遍历以外,还有很多内置对象的方法,包括map,以及数组筛选元素filter等。

注:文章结尾处附深层次数组扁平化方法操作。

作为引用数据类型的一种,在处理数组Array的时候,我们需要考虑到深拷贝和浅拷贝的情况
可以参考以下文章

常用数组操作方法

push末尾追加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @param push 将一个或多个元素添加到数组的末尾,返回该数组的新长度
*
* 集合apply和call合并数组
*
*/
let user = ["zhangsan", "lisi"];
console.log(user.push("xiaoming")); // 3
console.log(user); // ["zhangsan", "lisi", "xiaoming"]
let user1 = ["xiaowang", "xiaoming"];
let user2 = ["zhangsan", "lisi"];
console.log(Array.prototype.push.apply(user1, user2)); // 4
console.log(user1); // ["xiaowang", "xiaoming", "zhangsan", "lisi"]

pop删除数组末尾元素

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
*
* @param pop 方法从数组中删除最后一个元素,返回值是该元素。
*
* 如果数组是空数组,那么返回的是undefined
*
*/
let user = ["zhangsan", "lisi"];
console.log(user.pop()); // lisi
console.log(user); // ["zhangsan"]
let empArray = [];
console.log(empArray.pop()); // undefined

sort排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
*
* @param sort
*
* 使用原地算法对数组的元素进行排序,并返回数组。
* 默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的
* 由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。
*
* arr.sort([compareFunction])
*
* @param compareFunction
*
* 用来指定按某种顺序进行排列的函数。
* 如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
*
* 如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。
* 例如 "Banana" 会被排列到 "cherry" 之前。
* 当数字按由小到大排序时,9 出 * 现在 80 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 "80" 要比 "9" 要靠前。
* 如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:
* 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
* 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
* 备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
* 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
* compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
*
* firstEl
* 第一个用于比较的元素。
* secondEl
* 第二个用于比较的元素
*
*/
/**
*
* 基本用法
*
* */

const user = ["zhangsan", "lisi", "xiaoming", "xiaowang"];
user.sort();
console.log(user); // ["lisi", "xiaoming", "xiaowang", "zhangsan"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1); // [1, 100000, 21, 30, 4]

/**
*
* 自定义排序方法
*
* */
var numbers = [4, 2, 5, 1, 3];
let sortFun = function (a, b) {
return a - b;
};
numbers.sort(sortFun);
console.log(numbers); // [1, 2, 3, 4, 5]

shift数组开头添加元素 && unshift数组开头删除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
*
* @param shift
* 从数组中删除第一个元素,并返回该元素的值,如果删除空数组,返回值是undefined
*
* @param unshift
* 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度
*
* */
let user = ["zhangsan", "lisi"];
console.log(user.shift()); // zhangsan
console.log(user); // ["lisi"]
let empArray = [];
console.log(empArray.shift()); // undefined
let user1 = ["xiaoming", "xiaowang"];
console.log(user1.unshift("xiaoming1", "xiaowang1")); // 4
console.log(user1); // ["xiaoming1", "xiaowang1", "xiaoming", "xiaowang"]

数组合并concat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

/**
*
* @param concat
*
* 方法用于合并两个或多个数组。返回值是新数组,原数组不会发生更改
*
* 注:数组合并是浅拷贝
*
*/
let user = ["zhangsan", "lisi"];
let user1 = [["xiaowang"], { name: "xiaoming" }];
console.log(user.concat(user1)); // ["zhangsan","lisi",["xiaowang"],{name: "xiaoming"}]
console.log(user); // ["zhangsan", "lisi"]

indexOf查找元素 && includes查找元素是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
*
* @param indexOf
*
* 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1,
* 常用于判断数组是否存在某个元素
*
* @param includes
*
* 判断一个数组是否包含一个指定的值,返回值是布尔值 true 或者 false
*
*/
let user = ["zhangsan", "lisi"];
console.log(user.indexOf("lisi")); // 1
console.log(user.indexOf("xiaoming")); // -1
let user1 = ["zhangsan", ["xiaowang"], { name: "xiaoming" }];
console.log(user1.includes("zhangsan")); // true
console.log(user1.includes(["xiaowang"])); // false
console.log(user1.includes({ name: "xiaoming" })); // false

reverse反转数组

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
*
* @param reverse
*
* 反转数组元素,将原有数组倒叙显示,会改变元素的元素位置
*
*/
let user = ["zhangsan", "lisi", "xiaoming"];
console.log(user.reverse()); // ["xiaoming", "lisi", "zhangsan"]
console.log(user); // ["xiaoming", "lisi", "zhangsan"]
let user1 = ["zhangsan", ["xiaowang", "lisi"], { name: "xiaoming" }];
console.log(user1.reverse()); // [{name: "xiaoming"},["xiaowang", "lisi"],"zhangsan"]

数组切割成字符串join

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
*
* @param join
*
* 根据传入的参数字符串,对数组进行切割,返回值是使用参数拼接元素的字符串
* 如果数组只有一个元素,则不使用分割符号
*
*/
let user = ["zhangsan", "lisi", "xiaoming"];
console.log(user.join(" ")); // zhangsan lisi xiaoming
console.log(user.join("")); // zhangsanlisixiaoming
console.log(user.join(",")); // zhangsan,lisi,xiaoming
console.log(user.join({ a: 1 })); // zhangsan[object Object]lisi[object Object]xiaoming
console.log(user); // ["zhangsan", "lisi", "xiaoming"]

slice操作数组,替换,删除,新增

slice使用的范围较广,不同的参数可以实现对数组的删除,新增和替换等,使用的时候需要注意参数的具体使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
*
* @param slice
*
* 返回一个新的数组对象,
* 这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
*
* @param begin
* 提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。
* 如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
* 如果省略 begin,则 slice 从索引 0 开始。
* 如果 begin 超出原数组的索引范围,则会返回空数组
*
* @param end
*
* 提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。
* slice 会提取原数组中索引从 begin 到 end 的所有元素(包含 begin,但不包含 end)。
* slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。
* 如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。
* slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
* 如果 end 被省略,则 slice 会一直提取到原数组末尾。如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。
*
*/
const animals = ["ant", "bison", "camel", "duck", "elephant"];
console.log(animals.slice(2)); // Array ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4)); // Array ["camel", "duck"]
console.log(animals.slice(1, 5)); // Array ["bison", "camel", "duck", "elephant"]
console.log(animals.slice(-2)); // Array ["duck", "elephant"]
console.log(animals.slice(2, -1)); // Array ["camel", "duck"]
console.log(animals.slice()); // Array ["ant", "bison", "camel", "duck", "elephant"]
/**
*
* @param splice(start[, deleteCount[, item1[, item2[, ...]]]])
*
* 通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组
*
* 由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。
*
* @param start
*
* 指定修改的开始位置,默认从下标0开始。
* 如果超出了数组的长度,则从数组末尾开始添加元素;
* 如果是负值,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n);
* 如果负数的绝对值大于数组的长度,则表示开始位置为第0位。
*
* @param deleteCount
*
* 整数,表示要移除的数组元素的个数。
* 如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
* 如果 deleteCount 被省略了,
* 或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),
* 那么start之后数组的所有元素都会被删除。
*
* 如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
* @param item1, item2, ...
*
* 要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素
*
*/
const months = ["Jan", "March", "April", "June"];
months.splice(1, 0, "Feb"); // 下表为1,插入一个元素
console.log(months); // ["Jan", "Feb", "March", "April", "June"]
months.splice(4, 1, "May"); // 替换下标为4的元素
console.log(months); // ["Jan", "Feb", "March", "April", "May"]
let del = months.splice(1, 1); // 删除
console.log(del); // ["Feb"]
console.log(months); // ["Jan", "April", "May"]

every校验数组所有元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
*
* @param every
* 测试一个数组内的所有元素是否都能通过某个指定函数的测试,返回值是布尔值 true or false
* 备注:若收到一个空数组,此方法在任何情况下都会返回 true。
*
* arr.every(callback(element[, index[, array]])[, thisArg])
* callback
* 用来测试每个元素的函数,它可以接收三个参数:
*
* @param element 用于测试的当前值。
* @param index可选 用于测试的当前值的索引。
* @param array可选 调用 every 的当前数组。
*
* every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个会使 callback 返回 false 的元素。
* 如果发现了一个这样的元素,every 方法将会立即返回 false。
* 否则,callback 为每一个元素返回 true,every 就会返回 true。
*
* callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从未被赋值的索引调用。
* callback 在被调用时可传入三个参数:元素值,元素的索引,原数组。
* 如果为 every 提供一个 thisArg 参数,则该参数为调用 callback 时的 this 值。
* 如果省略该参数,则 callback 被调用时的 this 值,在非严格模式下为全局对象,在严格模式下传入 undefined。
*
*
* every 不会改变原数组。
* every 遍历的元素范围在第一次调用 callback 之前就已确定了。
* 在调用 every 之后添加到数组中的元素不会被 callback 访问到。
* 如果数组中存在的元素被更改,则他们传入 callback 的值是 every 访问到他们那一刻的值。
* 那些被删除的元素或从来未被赋值的元素将不会被访问到。
*
* */
const isBelowThreshold = (currentValue) => currentValue < 40;
const array1 = [1, 30, 39, 29, 10, 13];
console.log(array1.every(isBelowThreshold)); // true

some 测试数组中是不是至少有1个元素通过了被提供的函数测试。返回值是布尔值

1
2
3
4
5
6
7
8
9
/**
*
* @param some 测试数组中是不是至少有1个元素通过了被提供的函数测试。返回值是布尔值
*
* */
const array = [1, 2, 3, 4, 5];
const even = (element) => element % 2 === 0; //确认偶数
console.log(array.some(even)); // true;

深层次递归数组flat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

/**
* @param flat 按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
*
* var newArray = arr.flat([depth])
* @depth 指定要提取嵌套数组的结构深度,默认值为 1。
* */
let arr1 = [1, 2, [3, 4]];
console.log(arr1.flat()); // [1, 2, 3, 4]
let arr2 = [1, 2, [3, 4, [5, 6]]];
console.log(arr2.flat()); // [1, 2, 3, 4, [5, 6]]
let arr3 = [1, 2, [3, 4, [5, 6]]];
console.log(arr3.flat(2)); // [1, 2, 3, 4, 5, 6]
//使用 Infinity,可展开任意深度的嵌套数组
let arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
console.log(arr4.flat(Infinity)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let objArray = [{ name: "zhangsan", children: ["张三"] }];
console.log(objArray.flat(Infinity)); // [{ name: "zhangsan", children: ["张三"] }]

map遍历数组

1
2
3
4
5
6
7
8
9
10
/**
* @param map
*
* 创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成
*
* */
const array1 = [1, 4, 9, 16];
const map1 = array1.map((x) => x * 2);
console.log(map1); // [2, 8, 18, 32]

reduce和filter

reduce和filter的基本操作方法在之前的文章有提到过,这里不做复述

文章地址JavaScript 数组方法filter和reduce

数组操作示例:

数组对象根据属性整理数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 按照数组对象某个属性整理数据
*
* */
let user1 = [
{ name: "zhangsan", age: 21 },
{ name: "lisi", age: 20 },
{ name: "xiaoming", age: 20 },
];
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
let ageList = groupBy(user1, "age");
console.log(ageList); // {[{name: "lisi", age: 20},{name: "xiaoming", age: 20}],[{name: "zhangsan", age: 21}]}


数组扁平化-深层次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function flatten(array) {
var flattend = [];
(function flat(array) {
array.forEach(function (el) {
for (let i in el) {
if (Object.prototype.toString.call(el[i]) === "[object Array]")
flat(el[i]);
}
flattend.push(el);
});
})(array);
return flattend;
}
let user2 = [
{
name: "zhangsan",
age: 20,
child: [{ name: "xiaoming" }],
child1: [{ name: "xiaowang" }],
},
];
let flattenArray = flatten(user2);
console.log(flattenArray);

结尾

以上就是JavaScript中数组较为常用的方法,其他没有提及的方法,需要的同学可以查阅相关文章,或者留言,后续的文章整理然后作为补充。

源码地址

欢迎关注公众号:程序员布欧,不定期更新一些文章

创作不易,转载请注明出处和作者。