数组是我们一开始学习js的时候就接触到的数据结构,也是我们在开发中用得最多的,但是数组有很多我们一开始不知道的东西,而这些东西,往往会成为面试官经常会问的问题,笔者在准备实习和秋招的过程中深深地体会到了这一点。
今天我们就来揭开数组藏在海平面下的那一角。
数组的length属性
数组的length属性我们并不陌生,因为我们会经常使用这个属性来获取存在数组中数据的总数,以便进行一些操作,比如说分页。
其实,对于数组来说,length是数组的一个内置属性,数组会根据索引长度来更改length的值,这个特性会使得索引的长度大于数组元素个数,我们来观察如下代码:
let arr = [];
arr[2] = 'a';
console.log(arr.length);//3
在上述代码中,输出数组的长度为3,而数组只有一个元素‘a’,因为‘a’对应的索是2(数组索引从0开始)。而数组的第一个和第二个元素没有定义,所以值为undefined,即arr[0] = arr[1] = undefined。
伪数组
什么是伪数组?
伪数组就是像数组一样有length属性,也有0、1、2、3等属性的对象,其中0、1、2、3对应数组中的索引,且length属性是必须的。注意,伪数组不是数组。
如下代码就是一个伪数组的表示:
var fakeArray = {
"0": "first",
"1": "second",
"2": "third",
length: 3
};
下面我们来举两个在前端面试中面试官会问到的关于伪数组的的例子。
第一个例子:伪数组代码输出题
//以下代码输出什么?为什么?
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
obj.push(3)
console.log(obj)
在上述代码中,obj就是一个伪数组,因为它有一个length属性,并且我们给它部署了数组的slice和push方法,然后我们进行了三次push操作,那么经过push操作后,obj变成了什么呢?下面我们来一步步分析一下(下面把伪数组obj简称为数组)。
- 我们知道,push操作是在数组的尾部插入一个元素,由于obj中定义了length属性,值为2,所以数组下标(索引)的第一、第二项已经被占用,只能从数组的第三项(索引为2的那一项)插入。而obj中已经定义了索引 ‘2’ 和 ‘3’,所以第一次push会把索引 ‘2’ 对应的值3替换为1,数组长度length加1
- 第二次push操作索引 ‘3’ 对应的值4替换为2,数组长度length加1
- 经过前两次push操作,数组的length变为了4,第三次push使得length在加1,值变为5,那么对应的下标就是4,所以第三次push操作,会在数组中增加一项 ‘4’: 3
下面是改变后的obj:
第二个例子:伪数组变为真正的数组
题目描述:某公司 1 到 12 月份的销售额存在一个对象里面,如下:{1:222, 2:123, 5:888},请把数据处理为如下结构:[222, 123, null, null, 888, null, null, null, null, null, null, null]
我们观察一下上述需求,简单来说,需求就是让我们把一个对象转变为一个数组。但是对象怎么变成数组呢?好像我们并没有接触过这样的方法。
其实在js中可以把一个类似数组对象(也就是我们所说的伪数组)转为一个真正的数组,Array.from()方法可以实现这样的功能,下面我们先来介绍一下该方法。
Array.from()方法就是将一个类数组对象转换成一个真正的数组,该类数组对象需要具备一下条件:
- 该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。
- 该类数组对象的属性名(也就是转换后数组的索引)必须为数值型或字符串型的数字,如果为字符,那么转换后的数组元素全为undefined。
下面是代码实现:
let obj = {1:222, 2:123, 5:888};
//要保存12个月的销售额,那么数组的元素个数是12,这样的话类数组对象的length值为12
let arr = Array.from({length: 12});//创建一个长度为12的数组
let res = arr.map((item, index) => {
return obj[index+1] || null;
});
console.log(res);