发布时间:2023-08-15 19:30
前面讲到的对象虽然是非常强大的工具,但是,我们在编写代码时常常需要处理一些有序数据的集合。在有序集合中,元素的排列是有前后顺序的,例如:文章的列表、章节目录。由于对象并不能提供属性的有序访问,这种情况下,就需要我们使用新的数据结构数组。
我们可以通过两种方式创建一个空的数组:
let arr1 = new Array();//方式1
let arr2 = [];//方式2
由于第二种方式不仅简单,而且直观,我们常常采用第二种方式。
在声明一个数组时,我们可以直接进行初始化:
let arr = ['Chapter01','Chapter02','Chapter03','Chapter04','Chapter05'];
以上代码创建了一个包含五个元素的数组。
元素访问
我们可以通过下标的方式访问数组元素,需要注意的是,数组的编号是从0
开始的。
let arr = ['Chapter01','Chapter02','Chapter03','Chapter04','Chapter05'];
console.log(arr[0]);//访问第一个元素,注意下标是0
console.log(arr[3]);
console.log(arr[4]);
代码执行结果:
元素替换
通过下标,我们可以直接替换一个数组元素:
let arr = ['Chapter01','Chapter02','Chapter03','Chapter04','Chapter05'];
arr[1] = 'Chapter06';//数组变成了['Chapter01','Chapter06',...]
元素添加
通过下标向数组的末尾添加一个元素:
let arr = ['Chapter01','Chapter02']
arr[2] = 'Chapter03';//数组变为['Chapter01','Chapter02','Chapter03']
数组长度
通过数组的.length
属性可以获得数组中元素的个数
let arr = ['Chapter01','Chapter02']
console.log(arr.length)//2
循环添加
我们可以利用循环迅速创建一个任意长度的数组,这在我们编程中经常用到:
let arr = [];
for(let i = 0;i < 10;i++){
arr[i] = String(i);
}
元素类型
JavaScript
数组不限制元素的种类,在同一个数组中可以存储多种类型的数组:
let arr = [1, '2', { '3' : 3 }];
和对象一样,我们推荐在最后一个元素后添加
,
,这样在添加元素和移动元素的时候会非常容易:let arr = [ 'chapter1', 'chapter2', 'chapter3', ]
访问元素的方法并非一种,我们还可以通过at(idx)
方法访问数组的元素:
let arr = ['Chapter01','Chapter02','Chapter03'];
console.log(arr.at(2));
代码执行效果如下:
以上代码的执行效果和使用[idx]
方式完全相同,那么使用at
的意义在哪里呢?
最后一个元素
如果我们希望访问数组的最后一个元素,应该怎么办呢?
我们可以使用.length
属性实现:
let arr = ['Chapter01','Chapter02','Chapter03'];
console.log(arr[arr.length-1]);
但是这么做非常的不优雅,我们需要写两次数组的名字,此时,我们可以使用at(-1)
访问数组的最后一个元素。
let arr = ['Chapter01','Chapter02','Chapter03'];
console.log(arr.at(-1));
同理,访问倒数第二个元素可以使用arr.at(-2)
。
除了直接使用下标访问数组元素,数组还提供了四个方法用于在数组的首尾添加、删除元素:
push
:在数组尾部追加一个元素let arr = ['First'];
arr.push('Second');//此时arr变成了['First','Second']
pop
:在数组的尾部取出一个元素,等同于at(-1)
let arr = ['First','Second','Third'];
let last = arr.pop()//等同于arr.at(-1),arr此时为['First','Second']
console.log(last);//Third
shift
:从数组头部取出一个元素let arr = ['First','Second','Third'];
let first = arr.shift();//First,arr变为['First','Second','Third']
console.log(first);
unshift
:从数组头部插入一个元素let arr = ['Second'];
arr.unshift('First');//arr等于['First','Second']
栈是编程中最常用的线性数据结构,我们可以使用push/pop
方法,把数组当作栈使用。
let st = ['First'];
st.push('Second');//压栈
st.pop()//出栈
队列是另外一个常用的线性数据结构,我们可以使用push/shift
方法,把数组当作队列使用:
let que = ['First'];
que.push('Second');//入队
que.shift()//出队
清奇的脑回路
当然,我们可以使用shift/unshift
实现栈,通过unshift/pop
实现队列,只是通常情况下我们都不这么做~~
最简单的遍历数组的方式是for
循环:
let arr = ['First','Second','Third'];
for(let i = 0;i < arr.length; i++){
console.log(arr[i])
}
代码执行结果:
虽然这么做毫无问题,但是为了更加优雅,我们可以使用for ... of
语法:
let arr = ['First', 'Second', 'Third'];
for(let itm of arr){
console.log(itm)
}
代码执行结果和上面并无差别:
但是这么做也有一个缺点,就是没有办法获得元素下标,所以我们需要在合适的场景下做合适的选择。
我们可以使用数组的.length
属性获得数组的长度,但是,实际上数组的.length
属性并非数组里元素的个数,而是数组最大下标的值加一:
let arr = [];
arr[996] = 996;
console.log(arr.length)//997
代码的执行结果是不是和想象的不太一样:
我们通常情况下不这么使用数组,所以仍然可以使用.length
获取数组的长度。
从直观上理解,.length
应该是一个可读的属性,实际上,我们是可以修改.length
属性的值的:
let arr = [1,2,3,4,5,]
arr.length = 7;
console.log(arr.length)//length = 7
console.log(arr[6])//undefined
arr.length = 3;//length = 3,数组被截断
arr.length = 5;//length = 5,但是截断的数据不会回来了
console.log(arr.length)//5
console.log(arr[4])//undefined
代码执行结果如下:
修改length
会产生如下影响:
undefined
填充我们使用Array()
同样可以创建一个字符串,不过不常用,因为我们更喜欢[]
语法。
let arr = new Array('First','Second','Third');
Array()
还有一个不讨喜的特性:当我们使用单个数字参数时,会创建一个指定数字长度的空数组!
如果我们正好要创建一个具有单个数字的数组,就会出错。
let arr = new Array(4);
console.log(arr.length);//4
console.log(arr[3]);//undefined
为了避免出现不必要的错误,还是建议使用[]
,简单又方便。
JavaScript
的数组同样可以是多维的:
let arr = [
[1,1,1,],
[2,2,2,],
[3,3,3,],
]
数组的toString()
方法会把数组元素转为字符串,并以,
相隔:
let arr = [1,2,3]
console.log(arr.toString())//1,2,3
console.log(arr.toString()+1)//1,2,31
数组的本质是一个特殊的对象,因此我们不应该使用==
比较两个数组,就像不应该使用==
比较对象一样。
数组比较:
console.log([] == [])//false
console.log([1] == [1])//false
数组与基础类型比较:
console.log([] == 0)//true
console.log([] == '0')//false
console.log([1,2,3] == "1,2,3")//true
虽然其中有一定的规律,但是不建议使用==
比较数组,我们可以循环逐个比较元素,亦或者使用后面会介绍到的迭代。
数组是一个特殊的对象,方括号加下标的访问方式arr[3]
实际上就是对象的属性访问语法obj[key]
。
数组是对象的扩展,一个属性有序,而且具有length
属性的特殊对象,但是本质上仍然是对象。
我们在最初的文章中曾介绍,JavaScript
共有8
中数据类型,数组属于对象范畴。
如何验证数组是一个对象的本质呢?
实验一,数组变量存储的是引用:
let arr = [1,2,3]
let arr2 = arr;
console.log(arr2 === arr);//true
arr2.push(4)
console.log(arr.toString())//1,2,3,4
实验二,给数组添加属性:
let arr = [1,2,3]
arr.name = 'arr';
代码执行效果:
但是这么做就会破坏数组的特性,将数组变成一个普通的对象。
arr['name']='xiaoming'
3
的数组上使用arr[1000]=999
arr[1000]=1000
,arr[999]=999
如果我们不能把数组当作一个有序的数据结构,可以优先考虑对象。
在数组的末端插入数据比数组的头部插入数据要快,也就是push/pop
速度比shift/unshift
要快。
这是因为,从数组头部移除数据后,引擎会做三件事:
0
的值;length
;数组里面的元素越多,耗费时间越长,push/pop
操作在末尾,不会移动任何元素,所以速度很快。
数组是一个特殊的对象,其元素有序排列,使用下标访问数组元素
两种声明方式:[]
和new Array()
at(-1)
倒序访问元素
push/pop/shift/unshift
操作数组两端的元素
把数组用作栈、队列
数组元素遍历for
、for of
、for in
(不要使用这个)
不要使用==
比较数组