【JS数据结构与算法】数组-阿里云开发者社区

开发者社区> 开发与运维> 正文

【JS数据结构与算法】数组

简介: 几乎所有所有的编程语言中都支持了数组,JavaScript也不例外。在很多的编程语言中数组是用来存放一系列同种类型的值的,但是在我们的JS中,它却可以存放不同类型的值,而且它的长度还可以随着我们添加的值动态增加,所以在JS里面使用数组,会让我们有一种如丝般顺滑的感觉。

写在前面

几乎所有所有的编程语言中都支持了数组,JavaScript也不例外。在很多的编程语言中数组是用来存放一系列同种类型的值的,但是在我们的JS中,它却可以存放不同类型的值,而且它的长度还可以随着我们添加的值动态增加,所以在JS里面使用数组,会让我们有一种如丝般顺滑的感觉。
接下来的内容我们按如下图所示展开给大家介绍。
04.png

创建和初始化数组

在JS中创建和初始化数组有如下几种方式:

            //数组初始化、赋值方式
            let dataArray_01 = new Array(); //初始化一个空数组
            let dataArray_02 = new Array(5); //初始化一个长度为5的数组,如果里面有大于等于2个以上元素,就相当于给数组赋值
            let dataArray_03 = new Array('X北辰北', 'xbeichen.cn', 'Geov', 23); //创建一个含有四个元素的数组并赋值
            let dataArray_04 = []; //同dataArray_01
            let dataArray_05 = ['X北辰北', 'xbeichen.cn', 'Geov', 23]; //同dataArray_03

前三种方式我们使用JS内置的Array数组对象来实例化数组,后两种方式直接通过简写方式来实例化数组,这两种方式实例化出来的数组在用法上并没有差别,实际开发中我们推荐使用后两种中括号的方式去创建和初始化数组。
如果我们想获取数组中的元素个数,或者说想获取数组长度的话,可以直接使用length属性去获取,如下:

console.log(dataArray_01.length);

访问数组元素和迭代数组

访问数组中特定元素直接通过中括号加数组下标的方式访问,下标从0开始计数。
数组迭代可以通过一层for循环来实现,如下:

            //访问数组元素、迭代数组
            console.log(dataArray_05[1]); //输出'xbeichen.cn'
            for (let i = 0; i < dataArray_05.length; i++) {
                //迭代数组中所有元素,并输出
                console.log(dataArray_05[i]);
            }

在数组中添加元素和删除元素

在数组中添加和删除元素分为以下三种情况;

  • 在数组头部添加元素、删除元素
  • 在数组尾部添加元素、删除元素
  • 在数组中间某一位置添加元素、删除元素

下面我们就以上三种情况,分别来介绍下该如何去操作。

1、在数组头部添加元素、删除元素

在数组的头部位置添加元素的话,我们需要先将数组中每一项位置向后移动一位,腾出下标是0的位置,然后将要添加的元素添加到这个位置即可,代码如下:

            //头部添加元素
            let originData = [1, 2, 3, 4, 5];
            function preInsert(arr, value) {
                //遍历数组中每一项
                for (let i = arr.length; i >= 0; i--) {
                    //将每一项元素位置后移一位,腾出arr[0]的位置
                    arr[i] = arr[i - 1];
                }
                arr[0] = value; //arr[0]位置插入新值
                return arr;
            }
            console.log(preInsert(originData, 88)); //输出[88, 1, 2, 3, 4, 5]

除了上述直接上手自己实现之外,JS中的数组提供了一个方法,我们直接可以通过这方法来实现数组头部位置的元素添加,如下:

            originData.unshift(99);
            console.log(originData); //输出[99, 88, 1, 2, 3, 4, 5]

在数组头部位置删除元素的话,同理,我们只需要将数组中每一个元素往前移动一位即可,这样一来,数组的第二项就覆盖了原有的第一项元素,完成了数组头部位置元素的删除。但是这样做完的话,我们数组的长度是没有改变的,因为最后一项是undefined,所以我们新定义一个数组,将删除元素后的数组里面不是undefined的元素赋值到新数组,然后将新数组返回即可,如下:

            //头部删除元素
            let originData = [1, 2, 3, 4, 5];
            function preRemove(arr) {
                let newArray = []; //定义一个新数组,用于存放删除后数组中不是undefined的元素
                //遍历原数组,将每一项向前移动一位,覆盖前一位元素
                for (let i = 0; i < arr.length; i++) {
                    arr[i] = arr[i + 1];
                }
                //遍历完成覆盖后的数组,去除掉覆盖后的数组中最后一项值为undefined的元素
                for (let j = 0; j < arr.length; j++) {
                    if (arr[j] != undefined) {
                        newArray.push(arr[j]); //push方法用于向数组中尾部添加元素
                    }
                }
                return newArray;
            }
            console.log(preRemove(originData)); //输出[2, 3, 4, 5]

同样的,删除数组中第一个元素,JS中的数组提供了一个方法,我们直接可以通过这方法来实现数组头部位置的元素删除,如下:

            originData.shift();
            console.log(originData); //输出[3, 4, 5]

2、在数组尾部添加元素、删除元素

在数组的尾部添加元素相比于在头部位置添加元素的话显得特别简单,我们只需要在数组的最后位置增加一个空位,然后将值赋上去即可,这样操作可行是因为在JS中,数组是可以动态增长的,如下:

            //尾部增加元素
            let originData = [1, 2, 3, 4, 5];
            function laterInsert(arr, value) {
                //直接在数组最后位置添加空位并赋值即可,
                //因为数组实际长度是arr.length-1,arr[arr.length]就相当于在数组最后位置增加了一个空位
                arr[arr.length] = value;
                return arr;
            }
            console.log(laterInsert(originData, 88)); //输出[1, 2, 3, 4, 5, 88]

除了上述直接上手自己实现之外,JS中的数组提供了一个方法,我们直接可以通过这方法来实现数组尾部位置的元素添加,如下:

            originData.push(99);
            console.log(originData); //输出[1, 2, 3, 4, 5, 88, 99]

在数组最后位置删除元素,我们也不需要移动元素位置,只需要将原数组中的n-1(n是原数组长度)个元素赋值到一个新数组,然后返回这个新数组即可,如下:

            //尾部删除元素
            let originData = [1, 2, 3, 4, 5];
            function laterRemove(arr) {
                let newArray = []; //定义一个新数组
                for (let i = 0; i < arr.length - 1; i++) {
                    //循环遍历原数组的前n-1项,并将其每一项都赋值到新数组
                    newArray[i] = arr[i];
                }
                return newArray;
            }
            console.log(laterRemove(originData)); //输出[1, 2, 3, 4]

同样的,删除数组中最后一个元素,JS中的数组提供了一个方法,我们直接可以通过这方法来实现数组尾部位置的元素删除,如下:

            originData.pop();
            console.log(originData); //输出[1, 2, 3]

3、在数组中间某一位置添加元素、删除元素

在数组中间的某一位置要实现添加元素和删除元素的话其实我们自己写代码也是可以实现的,只需要将上述代码进行修改、增加判断条件这些就可以做到,在这里我们就不做详细的介绍。我们如果想在数组中间某一位置添加元素和删除元素的话,在这里给大家介绍splice()这个方法,这个方法既可以实现任意位置添加元素,也可以实现任意位置元素的删除,用法如下:

            //在中间某一位置删除元素
            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9];
            //从索引是2的位置开始,删除4个元素,即删除originData[2]、originData[3]、originData[4]、originData[5]
            originData.splice(2, 4);
            console.log(originData); //输出[1, 2, 7, 8, 9]
            //在中间某一位置添加元素
            let originData = [1, 2, 3, 4];
            //从索引是2的位置开始,删除0个元素,然后在此位置添加从第三个参数开始依次往后的各个元素
            //即在索引是2的位置处依次插入77、88、99这三个元素
            originData.splice(2, 0, 77, 88, 99);
            console.log(originData); //输出[1, 2, 77, 88, 99, 3, 4]

二维数组和多维数组

在JS中是不支持二维数组(矩阵)、多维数组这些的,它仅仅支持一维数组。但是我们可以通过数组套数组的方式来实现二维数组或者任一多维数组,代码如下:

            //定义二维数组、迭代二维数组
            let arrayData2D = []; //定义二维数组
            arrayData2D[0] = [1, 2, 3, 4, 5];
            arrayData2D[1] = [6, 7, 8, 9, 10];
            console.table(arrayData2D);
​
            //迭代
            for (let i = 0; i < arrayData2D.length; i++) {
                for (let j = 0; j < arrayData2D[i].length; j++) {
                    console.log(arrayData2D[i][j]);
                }
            }

01.png
多维数组的话跟上述一样,不过数组套数组部分我们直接通过for循环来做,如下:

            //定义三维数组、迭代三维数组
            let arrayData3D = [];
            for (let i = 0; i < 5; i++) {
                arrayData3D[i] = []; //初始化每一个纬度的数组
                for (let j = 0; j < 5; j++) {
                    arrayData3D[i][j] = []; //初始化每一个纬度的数组
                    for (let k = 0; k < 5; k++) {
                        arrayData3D[i][j][k] = i + j + k; //数组中的每一项存储当前坐标的数值之和
                    }
                }
            }
            console.table(arrayData3D);
​
            //迭代
            for (let i = 0; i < arrayData3D.length; i++) {
                for (let j = 0; j < arrayData3D[i].length; j++) {
                    for (let k = 0; k < arrayData3D[i][j].length; k++) {
                        console.log(arrayData3D[i][j][k]);
                    }
                }
            }

02.png
以上我们展示了一下三维数组的实例化和遍历,其他四维数组、五维数组……这些高维数组,我们只需要依次增加for循环去做就可以了,不过实际开发中三维和四维数组已经用的不太多了,所以大家没必要再去学习更高维的数组了。

JS数组方法

JS中的数组为我们提供了很多的方法,供我们去操作数组,能熟练使用这些方法的话会对我们接下来实现其他数据结构带来便利,我们来看看以下几种核心方法:
下表详述了数组的一些核心方法,其中的一些我们已经学习过了。

方 法 描 述
concat 连接 2 个或更多数组,并返回结果
every 对数组中的每个元素运行给定函数,如果该函数对每个元素都返回 true ,则返回 true
filter 对数组中的每个元素运行给定函数,返回该函数会返回 true 的元素组成的数组
forEach 对数组中的每个元素运行给定函数。这个方法没有返回值
join 将所有的数组元素连接成一个字符串
indexOf 返回第一个与给定参数相等的数组元素的索引,没有找到则返回 -1
lastIndexOf 返回在数组中搜索到的与给定参数相等的元素的索引里最大的值
map 对数组中的每个元素运行给定函数,返回每次函数调用的结果组成的数组
reverse 颠倒数组中元素的顺序,原先第一个元素现在变成最后一个,同样原先的最后一个元素变成了现在的第一个
slice 传入索引值,将数组里对应索引范围内的元素作为新数组返回
some 对数组中的每个元素运行给定函数,如果任一元素返回 true ,则返回 true
sort 按照字母顺序对数组排序,支持传入指定排序方法的函数作为参数
toString 将数组作为字符串返回
valueOf 和 toString 类似,将数组作为字符串返回

除了上述提出的方法之外,我们在文章开始的时候已经介绍过push()、pop()、shift()、unshift()、splice()这些方法,接下来我们再挑几个上述列表中的方法给大家介绍一下。

1、数组合并

数组的合并如果我们想自己编码实现的话很简单,只需要迭代各个数组中的元素,然后将其最终赋值到我们的结果数组中就可以,但是JS的数组对象给我们提供了一个用于数组合并的方法concat(),用法如下:

            //数组合并
            let arrayData_01 = [1, 2, 3];
            let arrayData_02 = [8, 9];
            let resultData = arrayData_01.concat(88, 'testValue', arrayData_02);
            console.log(resultData); //输出[1, 2, 3, 88, "testValue", 8, 9]

2、数组迭代——every

every()方法主要是用来检测数组中的所有元素是否满足某一条件,如果有一个元素不满足条件就直接返回false,剩余元素不再进行检测。
every()方法不会改变原数组。
使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.every(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //输出false,因为第一项就不满足,后面剩余元素不再检测

3、数组迭代——some

some()方法主要用来检测数组中是否有元素满足某一条件,如果有满足条件的元素直接返回true,剩余元素不再进行检测。
some()方法不会改变原数组。
使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.some(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //输出true,因为第一项不满足,但是第二项满足条件,所以返回true,后面剩余元素不再检测

4、数组迭代——forEach

forEach()方法主要是遍历数组中的每一项,并将其传递给回调函数,它跟for循环遍历数组是一样的。
使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            originData.forEach(function (value) {
                console.log(value);
            });
            //依次输出 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

5、数组迭代——map和filter

map()方法也会迭代数组,但是它会返回一个新数组,这个新数组中的值是回调函数中每一次的执行结果。
map()方法不会改变原数组。
使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.map(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //输出[false, true, false, true, false, true, false, true, false, true]

filter()方法主要用来筛选数组,它也会返回一个新数组,但是新数组中的值是符合回调函数条件的值。
filter()方法不会改变原数组。
使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.filter(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //输出[2, 4, 6, 8, 10]

6、数组迭代——reduce

reduce()方法的回调函数接收四个参数,但是平时我们仅用前两个,分别表示数组中的前一个元素和当前元素。reduce()方法的回调函数其实就是一个累加器,它会将数组中的值从左至右进行计算(缩减),最终数组中的所有值会计算得到一个结果,然后它将这个结果返回。所以reduce()方法非常适合求数组中所有元素的和。
reduce()方法不会改变原数组。
使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.reduce(function (preValue, laterValue) {
                return preValue + laterValue;
            });
            console.log(resultData); //输出55

7、ES6和ES6+中新增的数组方法

除了以上的几种方法之外,我们再来介绍几种ES6和ES7中新增加的操作数组的方法。

方 法 描 述
@@iterator 返回一个包含数组键值对的迭代器对象,可以通过同步调用得到数组元素的键值对
copyWithin 复制数组中一系列元素到同一数组指定的起始位置
entries 返回包含数组所有键值对的 @@iterator
includes 如果数组中存在某个元素则返回 true ,否则返回 false 。E2016新增
find 根据回调函数给定的条件从数组中查找元素,如果找到则返回该元素
findIndex 根据回调函数给定的条件从数组中查找元素,如果找到则返回该元素在数组中的索引
fill 用静态值填充数组
from 根据已有数组创建一个新数组
keys 返回包含数组所有索引的 @@iterator
of 根据传入的参数创建一个新数组
values 返回包含数组中所有值的 @@iterator

下面我们还是来挑几个常用的方法做一下介绍。

7.1、for……of循环迭代

JS中的数组循环除了for循环和forEach循环之外,在ES6中还提供了另一种循环方式,即for……of循环,下面来看下具体用法:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            for (const n of originData) {
                console.log(n);
            }
            //依次输出 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
7.2、@@iterator属性

ES6在JS中的Array类中新增加了一个@@iterator属性,这个属性通过如下方法来使用:

            let originData = [1, 2, 3, 4, 5];
            let iterator = originData[Symbol.iterator]();
            console.log(iterator.next().value); //输出1
            console.log(iterator.next().value); //输出2
            console.log(iterator.next().value); //输出3
            console.log(iterator.next().value); //输出4
            console.log(iterator.next().value); //输出5
            console.log(iterator.next().value); //输出undefined
            console.log(iterator.next().value); //输出undefined

上述方法在iterator.next().value迭代完之后,后面的数据值都是undefined。除了上述的迭代方法之外,还可以通过下面的方式迭代里面的数据:

            let originData = [1, 2, 3, 4, 5];
            let iterator = originData[Symbol.iterator]();
            for (const i of iterator) {
                console.log(i);
            }
            //输出1, 2, 3, 4, 5
7.3、entries、keys和values方法

entries()、keys()和values()三个方法都是ES6中新增的,为了获取数组中的迭代器,用法如下:

            let originData = [1, 2, 3, 4];
            let entriesValue = originData.entries();
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
​
            let keysValue = originData.keys();
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
​
            let valValue = originData.values();
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());

03.png

7.4、from方法

from()方法会根据一个已有数组返回一个新数组,此方法可以用来复制数组,也可以传入第二个参数来筛选数组或计算数组,如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData_01 = Array.from(originData);
            console.log(resultData_01); //输出[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
​
            let resultData_02 = Array.from(originData, function (value) {
                return value % 2 === 0 ? value : false;
            });
            console.log(resultData_02); //输出[false, 2, false, 4, false, 6, false, 8, false, 10]
7.5、Array.of方法

Array.of()方法根据传入的参数创建一个新数组。也可以用它来复制已有的数组,用法如下:

            let originData = Array.of(1, 2, 3);
            console.log(originData); //输出[1, 2, 3]
​
            let resultData = Array.of(...originData);
            console.log(resultData); //输出[1, 2, 3]
7.6、fill方法

fill()方法用于填充数据,支持全部填充,指定位置填充。用法如下:

            let originData = [1, 2, 3, 4, 5];
            originData.fill(88);
            console.log(originData); //输出[88, 88, 88, 88, 88]
​
            originData.fill(99, 2);
            console.log(originData); //输出[88, 88, 99, 99, 99]
​
            originData.fill(77, 1, 3);
            console.log(originData); //输出[88, 77, 77, 99, 99]
7.7、copyWithin方法

copyWithin()方法主要是用来将数组中指定位置和个数的元素复制到原数组的指定位置,如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            originData.copyWithin(0, 3);
            console.log(originData); //输出[4, 5, 6, 7, 8, 9, 10, 8, 9, 10]
            originData.copyWithin(0, 3, 5);
            console.log(originData); //输出[7, 8, 6, 7, 8, 9, 10, 8, 9, 10]

8、元素的排序

在介绍元素排序之前,先给大家介绍一个reverse()方法,这个方法会将我们数组中的元素反序输出,使用方法如下:

            let originData = [1, 2, 3, 4, 5];
            console.log(originData.reverse()); //输出[5, 4, 3, 2, 1]

除了上述可以将数组元素反序的方法之外,JS数组还向我们提供了一个供元素排序的方法,叫做sort()方法,在这个方法中通过传入一个自定义函数,数组元素会按照我们指定的顺序进行排序输出,如下:

            let originData = [3, 1, 2, 5, 4];
            originData.sort(function (a, b) {
                //实现降序
                return b - a;
            });
            console.log(originData); //输出[5, 4, 3, 2, 1]

9、元素搜索

JS的数组为我们提供了indexOf()和lastIndexOf()两个方法供我们在数组中查找元素,第一个方法返回与参数匹配的第一个元素的索引,第二个方法返回与参数匹配的最后一个元素的索引。除了这两个方法之外,ES6和ES7中还增加了一些供数组查找的方法。
ES6新增find()和findIndex()方法。
ES7新增includes()方法。
以上各种方法的使用,如下:

            //元素搜索
            let originData = [1, 2, 3, 4, 3, 3, 4];
​
            console.log(originData.indexOf(3)); //输出2
            console.log(originData.lastIndexOf(3)); //输出5
​
            let findValue = originData.find(function (value) {
                if (value % 2 === 0) {
                    return value;
                }
            });
            console.log(findValue); //输出2
            let findIndexValue = originData.findIndex(function (value) {
                if (value % 2 === 0) {
                    return value;
                }
            });
            console.log(findIndexValue); //输出1
​
            console.log(originData.includes(4)); //输出true

10、将元素输出为字符串

JS的数组中还提供了两个方法,可以将数组中的元素输出为字符串,使用方法如下:

            //元素输出为字符串
            let originData = [1, 2, 3, 4, 5];
            console.log(originData.toString()); //输出1,2,3,4,5
            console.log(originData.join('-')); //输出1-2-3-4-5

JS类型数组

我们以上介绍的数组里面是可以存储任意类型数据的,所以JS里的数组不是强类型的,但是我们可以用以下的方式声明和定义一个强类型的数组,这就是类型数组。

类型数组 数据类型
Int8Array 8 位二进制补码整数
Uint8Array 8 位无符号整数
Uint8ClampedArray 8 位无符号整数
Int16Array 16位二进制补码整数
Uint16Array 16位无符号整数
Int32Array 32位二进制补码整数
Uint32Array 32位无符号整数
Float32Array 32 位 IEEE 浮点数
Float64Array 64 位 IEEE 浮点数

以上就是类型数组支持的数据类型,我们简单来看下具体使用:

            //类型数组
            let typeArray = new Int32Array(5); //定义一个长度为5的整数数组
            typeArray[0] = 32.5; //赋值一个浮点数
            typeArray[1] = 22;
            console.log(typeArray); //输出[32, 22, 0, 0, 0]

总结

本篇文章中我们简单介绍了一下数组,包括数组的定义、具体的操作、二维数组和多维数组以及数组的元素增加和删除等。在JS中的数组其实和其他语言中的数组是不一样的,所以我们在介绍其他数据结构之前先给大家介绍一下数组这个数据结构,后面的其他数据结构都是在数组基础之上的,所以大家看完这篇文章后就可以接下来学习其他的数据结构了。我们下一篇给大家介绍一下JS中的另一个数据结构——栈。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章