数组常用的34个方法

941 阅读13分钟

本文将会讲解数组常用的34个方法

  • 我按照自己的关注点将这些方法分类(比如:sort()、reverse()和find()、findIndex()内部肯定也有遍历迭代的过程,但我这里将他们分别归类在排序和位置相关的类别中了)
  • 每个例子都附上了代码和最新版本Chrome浏览器运行的结果截图

tip: 本文按照图中从右侧向左侧的顺序讲解

开淦!!!


1. 形式转换

1.1 join()

  • 作用:将数组转化成字符串
  • 默认使用逗号作为分隔符
let arr = [1, 2, 3];
arr.join(); // "1,2,3"
  • 若想使用其他符号分隔数组中的每一项(比如-)
let arr = [1, 2, 3];
arr.join('-');  // "1-2-3"

1.2 toString()

  • 作用:将数组转换成字符串
let arr = [1, 2, 3];
arr.toString(); // "1,2,3"

1.3 toLocaleString()

  • 作用:将数组转换成字符串
let arr = [1, 2, 3];
arr.toLocaleString(); // "1,2,3"

tip:toLocaleString()和toString()看起来作用一样,有什么区别吗?

这两个方法是继承自对象的,所以所有的对象都可以使用这两个方法,数组使用这两个方法时是没有与区别的。今天想说的是这两个方法在其他场景下使用时的区别。

  • 当一个三位数字使用这俩方法的时候没有什么区别
let b = 123;
b.toString(); // "123"
b.toLocaleString(); "123"
  • 当一个三位以上的数字使用这两个方法的时候,toLocaleString()会实现千分位加逗号的效果
let b = 1234567890;
b.toLocaleString(); // "1,234,567,890"
b.toString(); // "1234567890"
  • 当转换日期格式的时候,toLocaleString()会返回一个格式化后的日期,toString()会返回一个标准格式时间
let date = new Date();
date.toLocaleStrin();
date.toString();

1.4 from()

1、 作用:将一个类数组对象或者可遍历对象转换成一个真正的数组

2、 Array.from()的用法1:将类数组对象转换为真正数组

先提一嘴什么是类数组?

下面代码中的arrayLike就是一个类数组

let arrayLike = {
    0: 'apple', 
    1: '100',
    2: '女',
    3: ['jane','john','Mary'],
    'length': 4
}
  • 若类数组中的键不是数字,返回length项值为undefined的数组
let arrayLike = {
    ’name': 'apple', 
    'age': '100',
    'sex''女',
    'friends': ['jane','john','Mary'],
    'length': 4
}
let arr = Array.from(arrayLike); // [undefined, undefined, undefined, undefined, undefined]
  • 类数组中的键是数字的字符串,和键名为数字的类数组返回值一样
let arrayLike = {
    '0''apple', 
    '1''100',
    '2''女',
    '3': ['jane','john','Mary'],
    'length': 4
}
let arr = Array.from(arrayLike); 
  • 没有length属性,返回空数组
let arrayLike = {
    0'apple', 
    1'100',
    2'女',
    3: ['jane','john','Mary']
}
let arr = Array.from(arrayLike); // []

所以得到类数组的特点

  • 类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。
  • 该类数组对象的属性名必须为数值型或字符串型的数字

3、 Array.from()的用法2:将Set结构的数据转换为真正的数组

4、Array.from()的用法3:接收第2个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组

let arr = [12,45,97,9797,564,134,45642];
let set = new Set(arr);
Array.from(set, item => item + 1);

5、Array.from()的用法4:将字符串转换为数组

let str = 'hello world!';
Array.from(str);

6、参数是一个真正的数组时,返回数组本身

Array.from([12, 45, 47, 56, 213, 4654, 154]);

1.5 of()

  • 作用:将一个或多个值转换成数组 用new Array()构造数组的时候,是有二意性的。

构造时,传一个参数,表示生成多大的数组。

构造时,传多个参数,每个参数都是数组的一个元素。

  • 而Array.of()方法,只有一个含义,of的参数就是表示转换后数组的元素

1.6 flat()

数组扁平化的其他方法

  • 按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回

  • 该方法返回一个新数组,对原数据没有影响

  • 参数: 指定要提取嵌套数组的结构深度,默认值为 1

  • 无参数时

const arr1 = [0, 1, 2, [3, 4]];
arr1.flat();
  • 有参数时,flat()的参数为2,表示要拉平两层的嵌套数组
const arr2 = [0, 1, 2, [[[3,4]]];
  • 不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
  • 如果原数组有空位,flat()方法会跳过空位
var arr4 = [1 2, 3, 4];
arr4.flat();

1.7 flatMap()

  • 对原数组的每个成员执行一个函数,相当于执行Array.prototype.map(),然后对返回值组成的数组执行flat()方法
  • 返回一个新数组,不改变原数组
  • 只能展开一层数组
[2, 3, 4].flatMap((x) => [x, x*2])

2. 栈和队列方法

2.1 push()

  • 数组末尾添加元素

2.2 pop()

  • 删除数组最后一个元素

2.3 shift()

  • 删除数组第一个元素

2.4 unshift()

  • 数组首个位置添加元素

添加方法和删除方法返回值区别?

  • 添加元素的方法push()和unshift()返回的是添加元素后新数组的长度
  • 删除元素的方法pop()和shift()返回的是删除的元素

3 排序

3.1 sort()

  • 对数字排序
let arr = [1,37,32,24,5,101];
arr.sort();
  • 对字母排序
var arr = ["a", "b", "A", "B"];
arr.sort();

巴特,好像和想象中的结果不一样,其实sort()

  • 默认是字母序升序
  • sort()的可选参数可以确定排序顺序,必须是个函数
  • 没有参数,数组中的元素将按照ASCII字符顺序进行排序

如果想得到想象中的排序结果,可以sort()中传入一个比较函数

按照文档中说明的,代码如下:

let arr = [1, 37, 32, 24, 5, 101];
   function compare(val1, val2) {
       if (val1 < val2) {
           return -1;
       } else if (val1 > val2) {
           return 1;
       } else {
           return 0;
       }
   }
arr.sort(compare);
  • 更常见的写法:
let arr = [1, 37, 32, 24, 5, 101];
arr.sort(function(x, y){
    return x - y;
});

按照我的理解是,在一个数组使用sort()方法时,会逐项的将数组中的元素传入到compare函数中作为参数...

3.2 reverse()

  • 颠倒数组中元素的顺序
var arr = [1, 5, 24, 32, 37, 101];
arr.reverse();

4 拼接

4.1 concat()

  • 作用:连接两个或多个数组
  • 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本
var arr = [1,3, 5, 7];
var arrCopy = arr.concat(9, [11, 13]);
  • 从上面测试结果可以发现:传入的不是数组,则直接把参数添加到数组后面。
  • 如果传入的是数组,则将数组中的各个项添加到数组中。但是如果传入的是一个二维数组呢?
var arr = [1, 3, 5, 7];
var arrCopy2 = arr.concat([9, [[11, 13]]);

会发现9被拉平到外层数组中,同事保留下内层数组[11,13]


5 创建子数组

5.1 slice()

  • 作用:从已有的数组中返回选定的元素组成的新数组

  • 当有1个参数时,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项

  • 当有2个参数时,该方法返回起始和结束位置之间的项,但不包括结束位置的项

  • 不改变原数组

  • 一个参数时,表示创建一个从此参数到最后一项最后的子数组(从3到最后一项)

var arr = [1, 3, 5, 7, 9, 11];
var arrCopy1 = arr.slice(1);
  • 有2个参数时,创建的子数组不包括end参数这一项
var arr = [1,3,5,7,9,11];
var arrCopy1 = arr.slice(1, 4);
  • 有2个参数,2个参数都是负数时(负数表示从后往前查找)
var arr = [1,3,5,7,9,11];
var arrCopy1 = arr.slice(-4 -1);

6 删改

6.1 splice()

我认为是非常非常强的方法,可以删除、插入和替换

1.删除功能

  • 删除元素,并返回删除的元素
  • 改变了原数组
  • 可以删除任意数量的项,指定2个参数:要删除的第一项的位置和要删除的项数。
var arr = [1,3,5,7,9,11];
var arrRemoved = arr.splice(0, 2);

2.插入功能

  • 向指定索引处插入元素
  • 提供3个参数:起始位置、 0(要删除的项数)和要插入的项
var array1 = [22, 3, 31, 12];
array1.splice(1, 0, 12, 35);

3.替换功能

  • 替换指定索引位置的元素
  • 可以向指定位置插入任意数量的项,且同时删除任意数量的项,指定3个参数:
  • 起始位置、要删除的项数和要插入的任意数量的项。
  • 插入的项数不必与删除的项数相等。
var array1 = [22, 3, 31, 12];
array1.splice(1, 1, 8);

7 位置相关

7.1 indexOf()

  • 返回某个指定的字符串值在字符串中首次出现的位置
  • 第2个参数可选,表示开始检索的位置
var arr = [1, 3, 5, 7, 7, 5, 3, 1];
arr.indexOf(5);
arr.indexOf(5, 2); // 表示从下标2处开始向后查找5,这一项就是5,返回5的下标2
arr.indexOf(5, 3); // 表示从下标处开始向后查找5,后面还有一个5,返回5的下标5

7.2 lastIndexOf()

参数同indexOf() 返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索

var arr = [1, 3, 5, 7, 7, 5, 3, 1];
arr.lastIndexOf(5); // 表示从数组末尾向前查找5,返回首次出现元素5的下标5
arr.lastIndexOf(5, 4); // 表示从下标4处开始向前查找5,返回首次出现元5的下标2

7.3 find()

  • 返回数组中符合测试函数条件的第一个元素,否则返回undefined
  • 参数
var arr = [1, 3, 5, 7, 9, 11];
arr.find((value, index, arr) => {
	return value > 5;
});
  • 该回调函数应当在给定的元素满足你定义的条件时返回true

7.4 fiindIndex()

  • 返回数组中符合测试函数条件的第一个元素的下标,否则返回undefined
  • 参数
var arr = [1, 3, 5, 7, 9, 11];
arr.findIndex((value, index, arr) => {
	return value > 5;
});

二者的异同?

  • 异:find()方法返回匹配的值,而 findIndex()返回匹配位置的索引。
  • 同:find()和 findIndex()方法均会在回调函数第一次返回true时停止查找。

8 归并

8.1 reduce()

  • 作用:

  • 参数

// 初始值是10,累加1-5,结果是25
var values = [1,2,3,4,5];
var sum = values.reduceRight(function(prev, cur, index, array){
    return prev + cur;
}, 10);   //数组一开始加了一个初始值10,可以不设默认0
console.log(sum)

reduce()方法可以搞定的东西,for循环,或者forEach方法有时候也可以搞定,那为啥要用reduce()? 大概是:通往成功的道路有很多,但是总有一条路是最捷径的,亦或许reduce()逼格更高...

这篇文章讲仅解reduce()最常用的累加用法,扩展用法请见 reduce()高级用法: initialVlue的作用、累加、累乘、数组去重、数组扁平化、计算数组中每个元素出现的次数


8.2 reduceRight()

  • reduceRight() 方法的功能和 reduce() 功能是一样的,不同的是 reduceRight() 从数组的末尾向前将数组中的数组项做累加。
  • 如果调用 reduceRight() 时提供了 initialValue 参数,则 accumulator 等于 initialValue,currentValue 等于数组中的最后一个值。如果没有提供 initialValue 参数,则 prevValue 等于数组最后一个值, currentValue 等于数组中倒数第二个值。

9 迭代

9.1 map()

  • 方法通过对每个数组元素执行函数来创建新数组
  • 方法不会对没有值的数组元素执行函数
  • 方法不会更改原始数组
  • 参数
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.map((item) => {
	return item * 2;
});

9.2 forEach()

  • 为每个数组元素调用一次函数(回调函数)
  • 参数
var arr = [1, 2, 3, 4, 5];
arr.forEach((item, index, arr) => {
	console.log(item + ' ' + index + ' ' +(a === arr));
});

9.3 filter()

  • “过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。
  • 不改变原数组
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var arr2 = arr.filter((item, index) => {
	return item > 8 && index % 3 == 0;
});

9.4 every()

  • 数组中所有项都满足条件,才会返回true。
  • 不改变原数组
  • 参数
var arr = [1, 2, 3, 4, 5];
arr.every((item) => {
    return item > 0;
}):

arr.every((item) => {
   return item > 10;
}):

9.5 some()

  • 只要有一项满足条件,就会返回 true。
  • 不改变原数组
  • 参数
var arr = [1, 2, 3, 4, 5];
arr.some((item) => {
    return item > 4;
}):

arr.some((item) => {
    return item > 5;
}):

9.6 keys()

  • 用于遍历数组。
  • 返回一个遍历器对象,可以用for…of循环进行遍历,对键名遍历
for(let i of (['a', 'b'].keys()) {
    console.log(i);
}

9.7 values()

  • 用于遍历数组
  • 返回一个遍历器对象,可以用for…of循环进行遍历,对键值遍历
for(let i of (['a', 'b'].values()) {
    console.log(i);
}

9.8 entries()

  • 用于遍历数组
  • 返回一个遍历器对象,可以用for…of循环进行遍历,对键值对遍历
for(let item of (['a', 'b'].entries()) {
    console.log(item);
}

调用遍历器对象的next方法

generator中可以使用next()得到返回值,若想了解generator,请看 generator


10 其他

10.1 isArray()

  • 返回一个遍历器对象,可以用for…of循环进行遍历,对键名遍历
  • 判断一个对象是否为数组,是数组返回true,否则返回false
Array.isArray([1,2,3]);
Array.isArray(0);
Array.isArray(true);
Array.isArray('123');

10.2 fill()

  • 用于将一个固定值替换数组的元素

  • 参数

  • 一个参数时

// 每一项都填充1
let arr = [1, 2, 3, 'cc', 5];
arr.fill(1);
  • 两个参数时
// 从下标为3处开始填充1
let arr = [1, 2, 3, 'cc', 5];
arr.fill(1,3);
  • 三个参数时
// 从下标为2到下标4(不包括4)填充1
let arr = [1, 2, 3, 'cc', 5];
arr.fill(1,2,4);

10.3 copyWIthin()

  • 从数组的指定位置拷贝元素到数组的另一个指定位置中。

  • 在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。

  • 参数

  • 2个参数时

// 表示从下标3处到最后拷贝到下标0处
[1, 2, 3, 4, 5].copyWithin(0, 3);
  • 3个参数时
// 表示从下标3处到下标4(不包括4)拷贝到下标0处
[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// 表示从倒数第2项处到倒数第1项(不包括倒数第1项)拷贝到下标0处
[1, 2, 3, 4, 5].copyWithin(0, -2, -1);

10.4 includes()

  • 判断一个数组是否包含一个指定的值,如果是返回 true,否则 false。
  • 参数

找到元素返回true,否则返回false

[1, 2, 3].includes(2);
[1, 2, 3].includes(4);
[1, 2, 3].includes(3, 3);
[1, 2, 3].includes(3, -1);

includes和indexOf()的区别?

includes()出来之前我们判断数组包含某个元素通常使用indexOf(),但是indexOf有两个小缺点:

  • 不够语义化,它返回的是元素第一次出现的下标,找不到时返回-1,通常要讲返回结果和-1比较。
  • indexOf()内部使用严格等式运算符(===)进行判断,会导致NaN的误判,如果数组中存在NaN,则无法找到。
NaN === NaN
lett arr = [NaN, 8, "hello"];
arr.indexOf(NaN); // arr中有NaN,但是没有返回结果
arr.includes(NaN);

整理的很匆忙,如有纰漏,欢迎指出。

引用1 引用2 引用3


我是洋洋李,一个前端搬砖小弟

一万年太久,只争朝夕,下次见