【数据结构与算法】JavaScript数组-操作数组方法总结

By 大Van家 on 2021-08-11
阅读时间 13 分钟
文章共 3.4k
阅读量

要点:JavaScript数组、操作数组的方法

几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构。
数组通常情况下用于存储一系列同一种数据类型的值。
但在 JavaScript 里,数组中可以保存不同类型的值。但我们还是要遵守最佳实践,别这么做(大多数语言都没这个能力)。

汇总:

不改变原数组的方法(8个):

ES5:

join、toLocateString、toStrigin、slice、cancat、indexOf、lastIndexOf

ES7:
includes

改变原数组的方法(9个):

ES5:
a.pop()、a.shift()、a.push()、a.unshift()、a.reverse()、a.splice()、a.sort()
ES6:
a.copyWithin() 、a.fill

对于这些能够改变原数组的方法,要注意避免在循环遍历中改变原数组的选项,比如: 改变数组的长度,导致遍历的长度出现问题。

遍历方法(12个):

js中遍历数组并不会改变原始数组的方法总共有12个:

ES5:
forEach、every 、some、 fliter、map、reduce、reduceRight、
ES6:
find、findIndex、keys、values、entries

关于遍历:

  • 遍历的效率
  • 尽量不要在遍历的时候,修改后面要遍历的值
  • 尽量不要在遍历的时候修改数组的长度(删除/添加)

创建和初始化数组

new Array()

1
2
3
4
5
6
7
8
9
const daysOfWeek = new Array(
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
);

[]

1
2
3
4
5
6
7
8
9
const daysOfWeek = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];

数组常见操作

添加元素

push(item)

添加一个元素到数组的最后位置(改变原数组

unshift(item)

在数组首位插入一个元素

splice(index, 0, item)

在指定索引位置插入元素(改变原数组

splice() 第二个参数为 0 时,表示插入数据。

1
2
3
4
let myArray = [1, 2, 3];
// 在 索引 0 的位置,插入 A
myArray.splice(0, 0, "A");
console.log(myArray); //--> ['A', 1, 2, 3]

删除元素

pop(item)

删除数组最后的元素。(改变原数组

shift(item)

删除数组首位的元素(改变原数组

unshift()

在数组开始删除一个元素(删且只删除1个),并返回 被删除的元素(改变原数组

splice(start, number)

删除指定索引位置的元素

例如:

1
2
3
4
let myArray2 = [1, 2, 3, 4, 5];
// 删除索引 4 位置起,2 个元素
myArray2.splice(4, 2);
console.log(myArray2); //--> [1, 2, 3]

修改元素

splice(index, number, item)

功能:从数组中删除元素、插入元素到数组中或者同时完成这两种操作。

输入:第一个参数为指定插入或删除的起始位置,第二个参数为要删除的个数。之后的参数表示需要插入到数组中的元素 。如果只有一个参数,默认删除参数后边的所有元素。

输出:返回一个由删除元素组成的数组。

注意:新建了一个数组,并修改了原数组

例1:修改指定索引位置的number个元素

1
2
3
4
let myArray3 = [1, 2, 3, 4, 5, 6];
// 修改 索引 1 的位置的元素为 AA
myArray2.splice(1, 1, "AA");
console.log(myArray3); //--> [1, "AA", 3, 4, 5, 6]

例2:修改指定索引位置的几个元素

1
2
3
4
let myArray4 = [1, 2, 3, 4, 5, 6, 7];
// 在 索引 2 的位置起,修改两个元素为 AA BB
myArray2.splice(2, 2, "AA", "BB");
console.log(myArray3); //--> [1, 2, "AA", "BB", 5, 6, 7]

join()

将数组中所有元素都转化为字符串并连接在一起。

reverse()

将数组中的元素颠倒顺序。(改变原数组

concat()

数组拼接的功能 ,返回新数组,原数组不受影响。

slice()

截取数组生成新数组,原数组不受影响。(浅拷贝数组的元素

返回的数组包含第一个参数指定的位置和所有到但不含第二个参数指定位置之间的所有元素。如果为负数,表示相对于数组中最后一个元素的位置。如果只有一个参数,表示到数组末尾。

参数:

begin(可选): 索引数值,接受负值,从该索引处开始提取原数组中的元素,默认值为0。

end(可选):索引数值(不包括),接受负值,在该索引处前结束提取原数组元素,默认值为数组末尾(包括最后一个元素)。

1
2
3
4
5
6
7
8
var aa = [1,2,3,4,5,6];
console.log(aa.slice(2)); //[3,4,5,6]
console.log(aa.slice(2,8)); //[3,4,5,6] 超过最大长度,只显示到最后结果
console.log(aa.slice(2,5)); //[3,4,5]
console.log(aa.slice(2,-1)); //[3,4,5] 相对于倒数第一个之前
console.log(aa.slice(2,-2)); //[3,4] 相对于倒数第二个之前
console.log(aa.slice(3)); //[4,5,6] 一个参数从第三个到最后
console.log(aa.slice(-2));//[5,6] 一个参数负值从倒数第二个到最后

如上:新数组是浅拷贝的,元素是简单数据类型,改变之后不会互相干扰。

如果是复杂数据类型(对象,数组)的话,改变其中一个,另外一个也会改变。

原因在定义上面说过了的:slice()是浅拷贝,对于复杂的数据类型浅拷贝,拷贝的只是指向原数组的指针,所以无论改变原数组,还是浅拷贝的数组,都是改变原数组的数据

toString()和toLocaleString()

将数组的每个元素转化为字符串,并且输入用逗号分隔的字符串列表。功能类似join();

遍历数组

indexOf()

定义: 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

语法:

array.indexOf(searchElement,fromIndex)
参数:

searchElement(必须):被查找的元素

fromIndex(可选):开始查找的位置(不能大于等于数组的长度,返回-1),接受负值,默认值为0。

严格相等的搜索:

数组的indexOf搜索跟字符串的indexOf不一样,数组的indexOf使用严格相等===搜索元素,即数组元素要完全匹配才能搜索成功。

注意:indexOf()不能识别NaN

1
2
3
4
let a=['啦啦',2,4,24,NaN]
console.log(a.indexOf('啦')); // -1
console.log(a.indexOf('NaN')); // -1
console.log(a.indexOf('啦啦')); // 0

lastIndexOf()

定义: 方法返回指定元素,在数组中的最后一个的索引,如果不存在则返回 -1。(从数组后面往前查找)

语法:

arr.lastIndexOf(searchElement,fromIndex)
参数:

searchElement(必须): 被查找的元素

fromIndex(可选): 逆向查找开始位置,默认值数组的长度-1,即查找整个数组。

关于fromIndex有三个规则:

  1. 正值。如果该值大于或等于数组的长度,则整个数组会被查找。
  2. 负值。将其视为从数组末尾向前的偏移。(比如-2,从数组最后第二个元素开始往前查找)
  3. 负值。其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。
1
2
3
4
5
let a=['OB',4,'Koro1',1,2,'Koro1',3,4,5,'Koro1']; // 数组长度为10
// let b=a.lastIndexOf('Koro1',4); // 从下标4开始往前找 返回下标2
// let b=a.lastIndexOf('Koro1',100); // 大于或数组的长度 查找整个数组 返回9
// let b=a.lastIndexOf('Koro1',-11); // -1 数组不会被查找
let b=a.lastIndexOf('Koro1',-9); // 从第二个元素4往前查找,没有找到 返回-1

sort()

默认情况下sort()方法没有传比较函数的话,默认按字母升序,如果不是元素不是字符串的话,会调用toString()方法将元素转化为字符串的Unicode(万国码)位点,然后再比较字符。所以用默认方法排序数据是有问题的。(改变原数组

1
2
3
4
5
6
7
8
var arr = [20,10,2,1,3];
arr.sort();// [1, 10, 2, 20, 3]
arr.sort(function(a,b){
return a-b; //升序
}); //[1, 2, 3, 10, 20]
arr.sort(function(a,b){
return b-a; //降序
}); //[20,10,3,2,1]

forEach()

从头至尾遍历数组,为每个元素调用指定函数

输入为一个待遍历函数,函数的参数依次为:数组元素、元素的索引、数组本身

注意:

  • 无法中途退出循环,只能用return退出本次回调,进行下一次回调。
  • 它总是返回 undefined值,即使你return了一个值。

map()

调用的数组的每一个元素传递给指定的函数,并返回一个新数组 ,不修改原数组

1
2
3
4
5
var arr = [2,3,4,5,6];
var bb= arr.map(function(x){
return x*x;
});
console.log(bb); // [4, 9, 16, 25, 36]

filter()

过滤功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。
可以巧妙的用来去重

1
2
3
4
5
var a = [1,2,3,4,5,6,3,1];
a.filter(function(v,i,self){
return self.indexOf(v) == i;
});
//[1, 2, 3, 4, 5, 6]

every()和some()

every() 判断数组中每一项都是否满足条件,只有所有项都满足条件,才会返回true。

some() 判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。

1
2
3
4
var arr = [1, 2, 3, 4, 5, 6];
arr.every(x=>x>0);//return true;
arr.every(x=>x>5);//return false;
arr.some(x=>x>5);//return true;

reduce()和reduceRight()

reduce() 两个参数:函数和递归的初始值。从数组的第一项开始,逐个遍历到最后

reduceRight() 从数组的最后一项开始,向前遍历到第一项

1
2
3
4
5
//可以用reduce快速求数组之和
var arr=[1,2,3,4];
arr.reduce(function(a,b){
return a+b;
}); //10

includes()

定义: 返回一个布尔值,表示某个数组是否包含给定的值

语法:

array.includes(searchElement,fromIndex=0)
参数:

searchElement(必须):被查找的元素

fromIndex(可选):默认值为0,参数表示搜索的起始位置,接受负值。正值超过数组长度,数组不会被搜索,返回false。负值绝对值超过长数组度,重置从0开始搜索。

includes方法是为了弥补indexOf方法的缺陷而出现的:

  1. indexOf方法不能识别NaN
  2. indexOf方法检查是否包含某个值不够语义化,需要判断是否不等于-1,表达不够直观
1
2
3
4
5
let a=['OB','Koro1',1,NaN];
// let b=a.includes(NaN); // true 识别NaN
// let b=a.includes('Koro1',100); // false 超过数组长度 不搜索
// let b=a.includes('Koro1',-3); // true 从倒数第三个元素开始搜索
// let b=a.includes('Koro1',-100); // true 负值绝对值超过数组长度,搜索整个数组

ES6新增

Array.of()

定义:返回由所有参数值组成的数组,如果没有参数,就返回一个空数组。

目的:Array.of() 出现的目的是为了解决上述构造器因参数个数不同,导致的行为有差异的问题。

1
2
let a = Array.of(3, 11, 8); // [3,11,8]
let a = Array.of(3); // [3]

Arrar.from()

定义:用于将两类对象转为真正的数组(不改变原对象,返回新的数组)。

参数:

第一个参数(必需):要转化为真正数组的对象。

第二个参数(可选): 类似数组的map方法,对每个元素进行处理,将处理后的值放入返回的数组。

第三个参数(可选): 用来绑定this。

1
2
3
4
5
6
// 1. 对象拥有length属性
let obj = {0: 'a', 1: 'b', 2:'c', length: 3};
let arr = Array.from(obj); // ['a','b','c'];
// 2. 部署了 Iterator接口的数据结构 比如:字符串、Set、NodeList对象
let arr = Array.from('hello'); // ['h','e','l','l']
let arr = Array.from(new Set(['a','b'])); // ['a','b']

copyWithin()

定义: 在当前数组内部,将指定位置的成员复制到其他位置,并返回这个数组。

语法:

array.copyWithin(target, start = 0, end = this.length)
参数:

三个参数都是数值,如果不是,会自动转为数值.

  1. target(必需):从该位置开始替换数据。如果为负值,表示倒数。
  2. start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
  3. end(可选):到该位置前停止读取数据,默认等于数组长度。使用负数可从数组结尾处规定位置。

浏览器兼容(MDN): chrome 45,Edge 12,Firefox32,Opera 32,Safari 9, IE 不支持

1
2
3
4
5
6
7
8
// -2相当于3号位,-1相当于4号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
var a=['OB1','Koro1','OB2','Koro2','OB3','Koro3','OB4','Koro4','OB5','Koro5']
// 2位置开始被替换,3位置开始读取要替换的 5位置前面停止替换
a.copyWithin(2,3,5)
// ["OB1","Koro1","Koro2","OB3","OB3","Koro3","OB4","Koro4","OB5","Koro5"]

fill()

定义: 使用给定值,填充一个数组。

参数:

第一个元素(必须): 要填充数组的值

第二个元素(可选): 填充的开始位置,默认值为0

第三个元素(可选):填充的结束位置,默认是为this.length

1
2
3
4
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

keys()&values()&entries()

遍历键名、遍历键值、遍历键名+键值,三个方法都返回一个新的 Array Iterator 对象,对象根据方法不同包含不同的值

1
2
3
array.keys()
array.values()
array.entries()

Tips: Please indicate the source and original author when reprinting or quoting this article.