JavaScript数组

数组(Array)是常用的数据集合类型,本文将介绍如何在JavaScript中使用Array类处理数组。

创建数组

创建数组对象有很多方法,最简单的就是使用一对方括号定义,如下面的代码。

JavaScript
<script>
    let arr1 = [];
    let arr2 = [1, 1, 2, 3, 5, 8];
    alert(arr1.length);  // 0
    alert(arr2); // 1, 1, 2, 3, 5, 8
</script>

对象arr1定义为空数组,第一个alert()函数调用会通过length属性显示元素的数量0;对象arr2包含了6个元素,第二个alert()函数会显示以逗号分隔的元素列表。

创建数组对象还可以使用Array类的构造函数,其参数设置如下:

  • 没有参数,创建一个元素数量为0的空数组。
  • 参数是一个大于或等于0的整数,指定元素的数量;数量大于0时,元素的默认值为undefined。
  • 一个非数值参数或多个参数,指定数组的元素。

下面的代码演示了相关应用。

JavaScript
<script>
    let arr1 = new Array();
    let arr2 = new Array(3);
    let arr3 = new Array("a");
    let arr4 = new Array(1, 1, 2, 3, 5, 8);
    alert(arr1.length);  // 0
    alert(arr2[0]); // undefined
    alert(arr3); // a
    alert(arr4); // 1, 1, 2, 3, 5, 8
</script>

arr1对象定义为空数组,第一个输出显示其元素数量0。arr2对象定义为包含3个元素的数组,第二个输出会显示第一个元素(索引0)的默认值undefined。arr3定义了包含字符a的数组,第三个输出会显示这个元素。arr4定义了包含6个元素的数组,第四个输出会显示逗号分隔的元素列表。

Array.of()方法,与Array类的构造函数应用相似,但在传递一个参数时需要注意,Array()构造函数传递一个整数参数时指定的是元素数量,而Array.of()方法则返回包含一个整数元素的数组,也就是说,Array.of()方法的参数都是在指定数组的元素。下面的代码演示了Array.of()方法的应用。

JavaScript
<script>
    let arr1 = new Array(3);
    let arr2 = Array.of(3);
    alert(arr1[0]);  // undefined
    alert(arr2[0]);  // 3
</script>

arr1对象定义为包含了三个元素的数组,元素值默认为undefined,第一个alert()函数调用显示第一个(索引0)元素的值undefined。arr2对象定义为包含一个元素的数组,第二个alert()函数调用显示第一个元素3。

Array.from()方法,参数为可迭代对象,返回由迭代对象的元素组成的数组。下面的代码演示了Array.from()方法的应用。

JavaScript
<script>
    let p = /abc/gi;
    let s = "abc,def,ABC,ghi";
    let arr = Array.from(s.match(p));
    alert(arr);
</script>

...运算符可以将数组展开为元素组成的参数列表,如下面的代码可以由数值和数组元素共同创建新的数组。

JavaScript
<script>
    let arr1 = [5, 6, 7];
    let arr = Array.of(1, 2, 3, ...arr1);
    alert(arr);
</script>

执行代码会显示1,2,3,5,6,7。

此外,Array.isArray(obj)方法可以判断参数obj是不是数组,如果obj是数组对象返回true,否则返回false。

访问和使用元素

访问数组的元素时,可以使用从0开始的数值索引,即第一个元素索引为0、第二个元素索引为1,以此类推。下面的代码演示了数组元素的赋值与读取。

JavaScript
<script>
    let arr = [1, 2, 3];
    arr[2] = 333;
    arr[5] = 6;
    alert(arr[0]); // 1
    alert(arr[2]); // 333
    alert(arr[5]); // 6
    alert(arr[3]); // undefined
    alert(arr.length); // 6
</script>

本例,首先定义的arr数组包含1、2、3三个元素。接下来,将第三个元素(索引2)赋值为333,即将3修改为333。请注意,arr[5]元素赋值为6,这是第六个元素,而原始数组只有三个元素,那么,第四、第五个元素没有赋值,读取它们的值时会返回undefined。最后,分别显示了第1、3、6、4个元素的值,并通过length属性显示了arr数组的元素数量6。

数组应用的便利性还在于,可以使用统一的代码逐个访问和处理数组元素。首先,可以使用索引为循环控制变量来访问元素,如下面的代码。

JavaScript
<script>
    let arr = [1, 2, 3];
    for (let i = 0; i < arr.length; i++) {
        alert(arr[i]);
    }
</script>

本例, for语句中循环控制变量i的范围是从0到数组元素数量减1。执行代码会显示1、2、3。

使用for...of循环也可以逐一访问数组元素,如下面的代码。

JavaScript
<script>
    let arr = [1, 2, 3];
    for (let e of arr) {
        alert(e);
    }
</script>

执行代码同样会显示1、2、3。

for循环中可以同时使用索引和元素,在for...of语句中同时使用索引值和元素值时,需要使用数组的entries()方法,如下面的代码。

JavaScript
<script>
    let arr = [1, 2, 3];
    for (let [i,e] of arr.entries()) {
        alert(`${i}:${e}`);
    }
</script>

entries()方法会返回索引值和元素数据的迭代,代码中,使用变量i处理索引值,变量e处理元素数据。执行代码会依次显示"0:1"、"1:2"、"2:3"。

数组对象的forEach()方法可以使用更加简洁的代码访问所有元素,如下面的代码。

JavaScript
<script>
    let arr = [1, 2, 3];
    arr.forEach(e => { alert(e); });
</script>

代码中,forEach()方法中使用=>运算符,运算符左侧为元素变量,运算符右侧使用一对花括号定义了对元素的操作代码,本例只是简单的显示元素的值,执行代码会分别显示1、2、3。

在forEach()方法中需要同时使用元素值和索引时,可以参考如下代码。

JavaScript
<script>
    let arr = [1, 2, 3];
    arr.forEach((e,i) => { alert(`${i}:${e}`); });
</script>

代码中,在=>运算符的左侧使用(e,i)分别指定了元素变量和索引变量,处理代码中分别显示了索引和对应的元素数据,显示结果为0:1、1:2、2:3。

需要对所有元素进行相同的操作,如修改格式、计算等操作时,可以使用数组对象的map()方法,方法会返回每个元素分别处理后的新元素组成的数组对象。下面的代码演示了map()方法的基本应用。

JavaScript
<script>
    let arr1 = [1, 2, 3];
    let arr2 = arr1.map(e => e * 3);
    alert(arr2);
</script>

代码中,在arr1对象上调用了map()方法,方法的参数同样使用=>运算符,运算符左侧为元素变量,运算符右侧直接定义了元素的操作代码,这里会将每个元素都乘以3;map()方法会返回arr1数组每个元素都乘以3以后组成的新数组arr2,显示结果为3、6、9。

在map()方法中也可以同时使用元素值的索引,如下面的代码。

JavaScript
<script>
    let arr1 = [1, 2, 3];
    let arr2 = arr1.map((e, i) => e * 3 + i);
    alert(arr2);
</script>

代码中,在=>运算符的左侧使用(e,i)定义了元素变量和索引变量,在=>运算符的右侧指定新元素值为元素原数据乘以3后加上索引值,执行结果会显示3、7、11。

添加、删除和替换元素

添加和删除元素有几个基本的方法,如:

  • push(e)方法,将e添加到数组的最后一个元素。e可以指定一个或多个参数。如果需要将一个数组的所有元素添加到当前数组,可使用...运算符展开数组元素。
  • unshift(e)方法,将e添加到数组的第一个元素。同样可以添加一个或多个元素,或者使用...运算符展开数组元素。
  • pop()方法,删除最后一个元素,并返回此元素。
  • shift()方法,删除第一个元素,并返回此元素。

下面的代码演示了push()和unshift()方法的应用。

JavaScript
<script>
    let arr1 = [1, 2, 3];
    let arr2 = [4, 5, 6];
    arr1.push(4, 5, 6);
    alert(arr1); // 1,2,3,4,5,6
    arr1.unshift(...arr2);
    alert(arr1); // 4,5,6,1,2,3,4,5,6
</script>

delete运算符可以删除元素的定义,如delete arr[i],此时再读取arr[i]元素数据时会返回undefined。

splice()可以删除或替换元素,参数设置包括:

  • 参数一,指定删除元素的起始索引。
  • 参数二,指定删除多少元素,不指定时会从指定位置开始删除以后的所有元素。
  • 第三个参数开始一一列出删除元素的替换元素。

此外,splice()方法还会返回删除的元素组成的数组,没有删除元素时返回空数组。

下面的代码,先来看前两个参数的应用,即执行元素的删除操作。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    alert(arr.splice(1, 3)); // 2,3,4
    alert(arr); // 1,5,6
    arr = [1, 2, 3, 4, 5, 6];
    alert(arr.splice(3)); // 4,5,6
    alert(arr); // 1,2,3
</script>

下面的代码会通过第三个参数开始指定被删除元素的替换元素。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    alert(arr.splice(1, 3,222,333,444)); // 2,3,4
    alert(arr); // 1,222,333,444,5,6
</script>

代码中,第一个输出显示了删除的元素2,3,4,第二个输出显示了元素替换后的结果1,222,333,444,5,6。

需要将一个元素插入指定位置时,也可以使用splice()方法,如下面的代码。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    alert(arr.splice(2, 0, 99)); // []
    alert(arr); // 1,2,99,3,4,5,6
</script>

代码中,splice()方法的第一个参数指定插入的索引位置,参数二设置为0,即不删除任何元素;第三个参数设置为插入的元素,本例会将99添加到第三个元素的位置。

数组对象的concat()方法可以将另一个数组的元素添加到当前数组,并返回合并后的新数组。下面的代码演示了相关应用。

JavaScript
<script>
    let arr1 = [1, 2, 3];
    let arr2 = [4, 5, 6];
    let arr3 = arr1.concat(arr2);
    alert(arr3);  // 1,2,3,4,5,6
</script>

请注意,push()和unshift()方法会在数组对象上直接添加元素,而concat()会返回新的数组对象。

排序

数组对象的sort()方法默认会对元素进行升序排列,如下面的代码。

JavaScript
<script>
    let arr = [8, 3, 6, 1, 9, 0, 5];
    arr.sort();
    alert(arr); // 0,1,3,5,6,8,9
</script>

sort()方法也可以通过参数设置排序方法,参数应该是一个函数或者是=>运算表达式,而函数返回值或=>运算符右侧代码运算结果应是一个数值,如比较的两个元素是a和b,而a-b小于0时,a排在b的前面,大于0时,a排在b的后面,等于0则保持位置;即默认的升序排列算法。下面的代码会指定数组元素降序排列。

JavaScript
<script>
    let arr = [8, 3, 6, 1, 9, 0, 5];
    arr.sort((a, b) => b - a);
    alert(arr); // 9,8,6,5,3,1,0
</script>

实际应用中,更加复杂的排序算法可以在sort()方法的参数中通过函数来实现。

reverse()方法可以让元素反向排列,即颠倒元素的顺序,下面的代码演示了reverse()方法的应用。

JavaScript
<script>
    let arr = [1, 3, 2];
    arr.reverse();
    alert(arr); // 2,3,1
</script>

查询与过滤元素

数组对象的includes()方法可以判断元素是否存在,存在时返回true,不存在返回false,下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3];
    alert(arr.includes(2));  // true
    alert(arr.includes(5));  // false
</script>

indexOf()方法可以返回元素第一次出现的索引位置,查找的元素不存在时返回-1。lastIndexOf()方法可以返回元素最后一次出现的索引位置,元素不存在时返回-1。下面的代码演示了这两个方法的应用。

JavaScript
<script>
    let arr = [1, 2, 3, 5, 2, 6];
    alert(arr.indexOf(2));  // 1
    alert(arr.indexOf(9)); // -1
    alert(arr.lastIndexOf(2));  // 4
    alert(arr.lastIndexOf(9)); // -1
</script>

filter()方法可以根据条件过滤元素,方法的参数需要指定函数或=>运算表达式,函数返回值或运算表达式结果是true时返回元素,结果是false时不返回元素;filter()方法会返回满足条件的元素组成的新数组。下面的代码演示了相关应用。

JavaScript
<script>
    let arr1 = [1, 2, 3, 5, 2, 6];
    let arr2 = arr1.filter(e => e % 2 === 1);
    alert(arr2);  // 1,3,5
</script>

代码中,会将arr1中的奇数挑选出来保存到arr2数组,最终显示为1,3,5。

需要按索引过滤数据时,可以参考如下代码。

JavaScript
<script>
    let arr1 = [1, 2, 3, 5, 2, 6];
    let arr2 = arr1.filter((e,i) => i % 2 === 1);
    alert(arr2);  // 2,5,6
</script>

代码中会挑选索引为奇数的元素,显示结果为2,5,6。

find()方法的应用与filter()方法相似,区别在于,find()只返回第一个满足条件的元素,没有找到时返回undefined。下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3, 5, 2, 6];
    alert(arr.find(e => e % 3 === 0));  // 3
    alert(arr.find(e => e % 7 === 0));  // undefined
</script>

findIndex()方法返回第一个满足条件的元素的索引值,没有找到元素时返回-1,下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3, 5, 2, 6];
    alert(arr.findIndex(e => e % 3 === 0));  // 2
    alert(arr.findIndex(e => e % 7 === 0));  // -1
</script>

合并元素

数组对象的join()方法可以返回指定分隔符连接所有元素的字符串,默认使用逗号(,)连接。下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3];
    alert(arr.join()); // 1,2,3
    alert(arr.join("-")); // 1-2-3
</script>

代码中,第一个输出显示了使用默认的逗号(,)连接元素的字符串,第二个输出显示了使用连接符(-)连接元素的字符串。

数组对象的toString()方法也可以返回逗号分隔的元素所组成的字符串,与没有参数的join()方法调用结果相同。请注意,在示例中直接使用alert()函数显示数组对象时,实际显示的就是toString()方法返回的内容。

截取、填充和复制

数组对象的slice()方法用于截取指定范围的元素,并返回截取元素组成的新数组对象,其参数设置如下:

  • 参数一,指定开始截取的元素的索引值,截取内容包含此元素。
  • 参数二,指定截取结束位置的索引值,截取内容不包含此元素。如果不指定,则截取由开始位置以后的全部元素。

下面的代码演示了slice()方法的应用。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    alert(arr.slice(2, 5)); // 3,4,5
    alert(arr.slice(2)); // 3,4,5,6
</script>

此外,slice()方法的参数还可以使用负数,此时,负数的绝对值表示倒数第几个元素,如-1为最后一个元素,-2为倒数第二个元素,以此类推。下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    alert(arr.slice(-4, -1)); // 3,4,5
    alert(arr.slice(-2)); // 5,6
</script>

fill()方法可以填充数组元素,其中,参数一为填充的值,参数二与参数三与slice()方法的参数设置相同,用于设置填充的范围,不设置范围时,会使用指定的值填充所有元素。下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    arr.fill(99, 2, 5);
    alert(arr); //  1,2,99,99,99,6
    //
    arr = [1, 2, 3, 4, 5, 6];
    arr.fill(0);
    alert(arr);  // 0,0,0,0,0,0
    //
    arr = [1, 2, 3, 4, 5, 6];
    arr.fill(99,3);
    alert(arr);  // 1,2,3,99,99,99
    //
    arr = [1, 2, 3, 4, 5, 6];
    arr.fill(99, -2);
    alert(arr);  // 1,2,3,4,99,99
</script>

copyWithin()方法可将指定范围的元素复制到其它位置,参数一设置目标位置的索引,参数二和参数三指定复制元素的范围,设置方法与slice()方法的参数相似。下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    arr.copyWithin(0, 3); 
    alert(arr); // 4,5,6,4,5,6
</script>

代码中,将第4个元素开始的元素(4,5,6)复制到第一个元素的位置,会覆盖元素1,2,3,最终,arr数组的元素变为4,5,6,4,5,6。

判断所有元素是否满足条件

every()方法的参数可以通过函数或=>表达式设置判断条件,所有元素都满足条件时方法返回true,否则返回false。some()方法的参数同样可以通过函数或=>表达式设置判断条件,只要有一个元素满足条件即返回true,所有元素都不满足条件返回false。下面的代码演示了相关应用。

JavaScript
<script>
    let arr = [1, 2, 3, 4, 5, 6];
    alert(arr.every(e => e % 2 === 0)); // false
    alert(arr.some(e => e % 2 === 0)); // true
</script>

代码中,every()和some()方法中的判断条件都是判断元素是否为偶数,every()方法返回false,some()方法返回true。

元素的计算

reduce()方法可以对数组中相邻的元素进行操作,典型的应用就是完成元素的计算工作。方法的参数一指定元素的操作;参数二指定计算的初始值,如果不指定则第一个元素的值为初始值。下面的代码会完成数组元素的累加操作。

JavaScript
<script>
    let arr = [1, 2, 3];
    alert(arr.reduce((a, b) => a + b, 0)); // 6
</script>

代码中,将初始值设置为0,不会改变元素相加的结果,如果是乘法运算,则初始值应该设置为1,如下面的代码。

JavaScript
<script>
    let arr = [1, 2, 3];
    alert(arr.reduce((a, b) => a * b, 1)); // 6
</script>

reduceRight()方法与reduce()方法的功能相似,只是reduceRight()方法会从最后一个元素向前遍历元素。

此外,Math.max()和Math.min()方法中,可以将数组使用...运算符展开为参数,计算数组元素中的最大值和最小值,如下面代码。

JavaScript
<script>
    let arr = [1, 2, 3];
    alert(Math.max(...arr)); // 3
    alert(Math.min(...arr)); // 1
</script>

多维数组

多维数组可以通过将数组元素定义为数组来模拟,如下面的代码。

JavaScript
<script>
    let arr = [[1, 2, 3], [4, 5, 6]];
    alert(arr[1][1]);  // 5
</script>

需要将多维数组的元素转换成一维数组时可以flat()方法,如下面的代码。

JavaScript
<script>
    let arr1 = [[1, 2, 3], [4, 5, 6]];
    let arr2 = arr1.flat();
    alert(arr2);  // 1,2,3,4,5,6
</script>

将多维数组转换为一维数组时,同时对元素进行操作可以使用flatMap()方法,如下面的代码。

JavaScript
<script>
    let arr1 = [[1, 2, 3], [4, 5, 6]];
    let arr2 = arr1.flatMap(e => e.filter(x => x % 2 === 1));
    alert(arr2);  // 1,3,5
</script>

本例,数组arr2中会保存arr1中的奇数1,3,5。flatMap()方法中,元素e表示arr1中的元素[1,2,3]和[4,5,6],然后分别在这两个元素的数组中调用filter()方法,只提取奇数数值;操作完成后将所有提取的奇数保存到arr2数组中。

请注意,flat()和flatMap()只能向下展开一级数组,如果有多级数组,还会返回数组,如下面的代码。

JavaScript
<script>
    let arr1 = [[1, 2], [[3, 4], [5, 6]]];
    let arr2 = arr1.flat();
    for (let e of arr2) {
        alert(e);
    }
</script>

本例,arr2的元素会是1,2,[3,4],[5,6],也就是说flat()方法只向下展开了一级,arr1数组的第一个元素是[1,2],会展开为1和2;第二个元素是[[3, 4], [5, 6]],展开后是[3, 4]和[5, 6]两个数组元素。