这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
在 JavaScript 中,数组是一种特殊的对象类型,用于存储有序的集合,它内置了很多用于操作数组元素的方法。详细列表可以参看 MDN——Array。
下文介绍一些常用的数组使用技巧,帮助你提高开发效率。
数组的判断
Array.isArray
:最靠谱的判断数组的方法。
let arr = [1,2,3];
Array.isArray(arr); // => true
使用 instanceof
进行判断:
arr instanceof Array; // => true
使用 Object.prototype.toString
进行判断:
Object.prototype.toString.call(arr); // => [Object Array]
对象的键值调换
假设有个对象 {a: 1, b: 2, c: 3}
,我们常常会想知道某个值对应的键名是什么,如果有个键值调换的对象 {1: a, 2: b, 3: c}
就好了。借助以下几个方法,几行代码就能够获取这么一个对象。
Object.entries
:将对象转成键值对的数组:
let obj = {a:1,b:2,c:3};
Object.entries(obj); // => [["a",1],["b",2],["c",3]]
Object.fromEntries
:将键值对数组转成键值对对象:
let arr = [["a",1],["b",2],["c",3]];
Object.fromEntries(arr); // => {a: 1, b: 2, c: 3}
Array.prototype.reverse
:将数组中元素进行倒序排序,并返回该数组:
[1,2,3].reverse(); // => [3,2,1]
Array.prototype.map
:接收一个函数,返回数组每个元素调用函数后返回的值组成的数组:
let arr = [1, 2, 3, 4];
let arr2 = arr.map(x => x*2); // => [2, 4, 6, 8]
综合使用以上四个方法,就能迅速得到键值调换后的新对象了,如下所示:
let obj = {a: 1, b: 2, c: 3};
let reverseObj = Object.fromEntries(Object.entries(obj).map((item)=>{
return item.reverse();
}));
console.log(reverseObj); // => {1: 'a', 2: 'b', 3: 'c'}
另外,双向映射还可以这样在赋值的时候实现:
let obj = {};
obj[ obj['a'] = 1 ]='a';
console.log(obj); // => {1: 'a', a: 1}
实现字符串的重复
面试官:给 String 类型添加一个
repeat
法,能够将当前字符串重复 n 次,示例如下:
let s = '123'.repeat(3); // s => '123123123'
这里介绍几个数组方法:
new Array(length)
:数组的构造函数,接受一个参数,作为数组的长度。
let arr = new Array(10);
// 相当于
let arr = [];
arr.length = 10;
Array.prototype.fill
:接受三个参数(填充值,起始索引,终止索引),填充数组项,使用如下:
const array1 = [1, 2, 3, 4];
console.log(array1.fill(0, 2, 4));
// => [1, 2, 0, 0]
console.log(array1.fill(5, 1)); // 省略终止索引,默认为最后一位
// => [1, 5, 5, 5]
console.log(array1.fill(6)); // 省略起始终止索引,默认全填充
// => [6, 6, 6, 6]
Array.prototype.join
:将一个数组的所有元素连接成一个字符串并返回这个字符串,接受一个参数作为连接符,默认连接符为「,
」,示例如下:
let arr = ['one', 'two', 'three'];
arr.join(); // => one,two,three
arr.join('-') // => one-two-three
综合使用以上方法,一行代码实现 repeat
功能:
String.prototype.repeat = function (n) {
return new Array(n).fill(this).join('');
}
数组的拷贝
数组本质上是对象,所以它们的赋值是引用传值,这种赋值会出现一方的修改会导致另一方也被改变的情况,因为它们本质上还是同一个数组。
let arr1 = [1,2,3];
let arr2 = arr1;
arr2[0] = 0; // 对 arr2 进行修改,会导致 arr1 也被改变
console.log(arr1[0]); // => 0;
使用 Array.prototype.slice
方法,可以生成一个新数组进行赋值,避免引用传值:
let arr1 = [1,2,3];
let arr2 = arr1.slice();
arr2[0] = 0;
console.log(arr1[0]); // => 1;
也可以通过 Array.prototype.concat
方法实现:
let arr1 = [1,2,3];
let arr2 = arr1.concat();
arr2[0] = 0;
console.log(arr1[0]); // => 1;
数组去重
利用 Set 进行去重:
let arr = [1,2,3,1,2,3,4,5,6,1,1,1];
arr = Array.from(new Set(arr));
// 或者
arr = [...new Set(arr)]
数组扁平化
所谓数组扁平化,就是将数组类型的元素进行拆分,例如:
[[1], [2,3], [4,5,6]] => [1,2,3,4,5,6]
Array.prototype.flat
:该方法接受一个参数,进行递归遍历数组,将数组类型元素拆分并合并到原数组,递归的层数由传入的参数决定,默认递归一层。
let arr = [1,[2,3,[4,5,[6,7]]], [8,9,[10],[11]]];
arr.flat(); // => [1,2,3,[4,5,[6,7]],8,9,[10],[11]]
arr.flat(3); // => [1,2,3,4,5,6,7,8,9,10,11]
在 ES6 中有「扩展运算符」,能够对数组进行展开,但是只能展开一层,通过递归使用就能够将数组完全展开。
let arr = [1,[2,3,[4,5,[6,7]]], [8,9,[10],[11]]];
arr = [].concat(...arr); // => [1,2,3,[4,5,[6,7]],8,9,[10],[11]];
// 使用循环实现展开所有子数组
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
console.log(arr) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
往数组中删除、插入、替换元素
面试官:写一段删除数组中最后三个元素的代码。
应该很多人会采用 「循环 + Array.prototype.pop
」的方式进行实现。其实,数组的 length 也是可以用来删除数组元素的。
let arr = [1,2,3,4,5,6,7]
arr.length = arr.length - 3;
console.log(arr); // => [1, 2, 3, 4]
通常使用 Array.prototype.splice
方法进行元素的删除、插入、替换。
let arr = [1,2,3,4,5,6,7];
// 传一个参数的时候,作为起始索引,删除之后的所有元素
arr.splice(arr.length - 3);
console.log(arr); // => [1, 2, 3, 4]
// 传递两个参数的时候,分别是起始索引和删除的个数
arr.splice(2, 2); // 在 [1,2,3,4]的基础上进行操作
console.log(arr); // => [1,2]
// 传递大于2个参数的时候,分别是起始索引、删除的个数以及插入的值
arr.splice(0, 2, 3, 3, 3); // 在 [1,2] 的基础上
console.log(arr); // => [3,3];
求数组所有值的和
Array.prototype.reduce
:提供一个函数,该方法对数组中的每个元素传入函数。函数返回值作为下一次调用的其中一个参数。
利用该方法实现数组和的代码如下:
let arr = [1,2,3,4];
arr.reduce((a, b) => a+b); // 10
该方法还可以接受一个初始值,如下所示:
arr.reduce((a, b) => {
return a+b;
}, 5); // => 15
最后
还有其它数组的使用技巧吗,欢迎评论区进行交流。