Skip to content

凡是通过 Array 构造方法创造的对象,都叫做数组,注意,伪数组一般是通过 Object 构造器创建的,不能叫数组。

Array - JavaScript | MDN

在 ES 5 之前,数组里的方法很少,数组里面的很多方法都是 ES 5 标准加上的。当然,这里介绍的所有属性和方法现在主流浏览器肯定都完全支持了,不需要考虑兼容性的问题。

前面已经介绍过的我们不会过多重复介绍,包括 slice 复制数组,splice 删除和插入,push 入栈,pop 出栈,也包括 shift 和 unshift。

静态成员 ​

刚刚我们才说了,我们可以通过 [].slice.call(伪数组),将一个伪数组转换为真数组,实际上,Array 构造函数中提供了一个方法,来帮助我们快速将伪数组转换为真数组。

js
function test(){
	var newArr = Array.from(arguments);
	console.log(newArr);//此时就是一个真数组
}
test(1,2,3);

那这里有一个问题,真数组是通过 Array 构造函数创建的对象,而假数组则不是,那如何判断一个东西是不是真数组呢,就可以通过 Array.isArray 方法来判断

js
var arr = [];
console.log(Array.isArray(arr));//true

如果读者有一定 JS 基础,可能会考虑 arr.constructor == Array 来判断,这种判断方式是不安全的,因为 constructor 属性是一个可读可写的属性,JS 并未对其进行保护。所以一旦该对象的 constructor 被篡改,那这个表达式就会判断错误。

除此之外,还有一个 Array.of() 方法,这个方法用于创建一个新数组,Array.of(第一项,第二项,...) 即可返回一个新数组,这个方法的出现是为了弥补 Array 构造函数直接调用时的缺陷,实际用的很少。

实例成员 ​

数组有非常多的实例成员,一些已经介绍过,不再赘述。

js
//很多时候,我们都需要让数组的每一项都填充为一个固定的数,我们通常称其为初始化,比如我要创建一个长为200的数组,要让其每一项都初始化为100,如果用已有的知识,那我们大概率需要用到循环,但JS提供了一个方法来快速实现这个功能
//Array.prototype.fill()
var arr = new Array(200);//创建了一个长度为200的数组
arr.fill(100);//每一项填充为100
console.log(arr);

//很多时候我们还需要将数组颠倒顺序,如果读者没有编程基础,可以新建一个新数组,然后将旧数组从后往前扫描,依次在新数组中插入。如果读者学过一些数据结构的知识,可能会考虑用双指针法来颠倒数组。
//不管用何种方法,让我们自己写都是很麻烦的,JS内部提供了这样的方法来颠倒数组
//Array.prototype.reverse()
var arr = [1,2,3,4,5];
var arr2 = arr.reverse();
console.log(arr,arr2);//[5, 4, 3, 2, 1] [5, 4, 3, 2, 1]
//可以看到,调用reverse之后,会将这个数组颠倒顺序,并且返回值也是这个颠倒顺序后的数组,这里有一个问题,就是这种方式其实改变了原数组,有时候我不需要这个功能,我希望在不改变原数组的前提下,或者说不产生任何影响的情况下,给我返回一个颠倒之后的新数组,这个也可以用另一个函数做到:Array.prototype.toReversed
var arr = [1,2,3,4,5];
var arr2 = arr.toReversed();
console.log(arr,arr2);//[1,2,3,4,5] [5, 4, 3, 2, 1]
//这个方法是一个2023年才受支持的新方法,在旧版浏览器中不受支持。
//对于不受支持的浏览器,我们可以使用arr.slice().reverse();来模拟arr.toReversed(),即先复制一份,将副本进行转置,从而不影响原数组。

//Array.prototype.sort()
//在JS中已经有一个sort函数,这个函数在前面我们甚至自己写过,不过这个JS内置的sort函数更好,sort函数接受一个回调函数作为参数
//sort函数会给回调函数传入两个参数,a和b,如果我们给的返回值大于0,说明a在b前面,小于0说明b在a前面,如果等于0,说明a和b顺序不变。
var arr = [3,22,5,1];
arr.sort();//这里有个大坑,这种默认的升序排序是按位进行比较的,所以我们会发现22排在3之前,所以我们一般不建议不传参数。
console.log(arr);//可见,sort函数会改变原有数组
//如果我们希望在不改变原有数组的情况下,返回给我们一个新数组,我们可以使用toSorted(),这也是一个2023年新支持的函数,用法一模一样
arr.sort(function (a,b){ //这样就可以实现升序排列
	return a-b;
});
//我们可以使用这个方法很轻松地实现随机打乱数组
arr.sort(function (a,b){
	return Math.random()-0.5;//生成一个-0.5到0.5的随机数
})

//我们观察到,以上的方法,都会改变数组原有的数据,当然,也介绍了两个扩展的方法,下面介绍一些不会改变原数据的方法。对原数据没有任何影响的函数,我们可以称为纯函数。

//Array.prototype.concat()
//该函数可以将多个数组拼接成一个新数组进行返回
var arr1 = [1,2];
var arr2 = [3,4];
var arr3= [5,6,7];
var newArr = arr1.concat(arr2).concat(arr3);//这个代码可能读者看不懂,arr1.concat(arr2)表示arr1后面拼接上arr2,此时得到一个新数组,这个新数组后面.concat(arr3),相当于把这个数组拼接上arr3。这种我们可以连续点的函数风格我们称为链式调用风格。
//concat其实允许多个参数,所以我们也可以写成arr1.concat(arr2,arr3)
//这是一个纯函数,没有副作用,不会改变原数组,后面的所有和数组相关的属性都是纯函数

//Array.prototype.includes()
//该函数非常好用,用于判断数组中是否存在一个满足条件的值
var arr = [1,2,3,4,5];
console.log(arr.includes(2));//arr中有2,所以返回true
console.log(arr.includes(2,3));//从下标为3的地方开始寻找,是否存在2,很显然下标为3后面不存在,返回false
//该函数的比较是用严格相等===来比较的,不会发生自动类型转换

//Array.prototype.forEach()
//以前遍历数组,用得是for循环,我们可以使用forEach函数更加方便地遍历数组
var arr = [1,2,3,4,5];
arr.forEach(function (item,index,array){
	console.log(`当前遍历的是第${index}项,值为${item},完整数组为${array}`);
});
//可以看到,调用这个函数后,会调用很多次这个回调函数,每次调用传入数组的一项,以及该项的下标,还有完整的数组。
//这个函数非常好用,强烈推荐

//Array.prototype.every()
//用于判断数组中是否所有的元素都满足指定条件,这里的条件通过回调函数传入
var arr = [2,3,4,5];
console.log(arr.every(function (item,i,array){
	return item < 10;
}));//判断是否所有数据都小于10,这里输出true

//Array.prototype.some()
//和every类似,只要有至少一个满足条件就返回true,否则返回false
var arr = [50,69,55];
arr.some(function (item,i,arr){
	return item>60;
});//由于arr[1]比60大,所以这里返回true

//Array.prototype.filter()
//遍历数组,将数组中所有满足条件的数据封装成一个新数组进行返回,注意,不会改变原数组
var arr = [60,2,43,69,80];
arr.filter(function (item,i,arr){
	return item>=60;
});//返回[60,69,80]

//Array.prototype.find()
//返回第一个满足条件的元素,如果没有找到,返回undefined
var arr = [20,2,43,69,80];
arr.find(function (item,i,arr){
	return item>=60;
});//返回[69]

//Array.prototype.findIndex()
//和find()类似,只不过返回的是下标,如果找不到,返回-1
var arr = [20,2,43,69,80];
arr.find(function (item,i,arr){
	return item>=60;
});//返回3

//Array.prototype.map()
//将数组的每一项映射成另外一项
var arr = [1,2,3,4,5];
arr.map(function (item,index,arr){
	return item++;//每一个都加一
});//返回[2,3,4,5,6]
//注意,不会改变原数组

//Array.prototype.reduce()
//一般用于统计,传入一个回调函数,这个回调函数接受两个参数,第一个为a,第二个为b
//首先,对于一个数组,会现将第一项传给a,第二项传给b,我这个函数会返回一个返回值
//紧接着将返回值再传给a,再将第三项传给b。依次类推。
var arr = [2,3,4,5];
arr.reduce(function (a,b){
	return a+b;
});//返回14
//以这个为例,先将2传给a,3传给b,调用函数,返回5,再将返回的这个5传给a,然后4传给b,返回9,再将返回的这个9传给a,5传给b,返回14
//如果数组只有一项,直接返回第一项的值,不会运行函数
//该函数支持第二个参数,为默认值,一般来说第一次是把第一项传给a,我们指定第二个参数之后,第一次就会把第二个参数传给a。

下面一个联系,有一个数字类型的数组,我现在要去掉所有的负数,对每一项进行平方,然后每一项翻倍,然后进行求和。

js
arr.filter(function (item){
	return item>=0;
}).map(function (item){
	return (item**2)*2
}).reduce(function (a,b){
	return a+b;
});

以笔记为镜,可以知得失