类数组对象的特点介于对象和数组之间:
- 类数组对象是一个对象,而不是数组;
- 虽然类数组对象是一个对象,却可以在它上面调用数组方法来操作它的正整数属性。
在深入了解类数组对象之前,我们先来分析一下数组。
1. 每个数组都有一个必须的"length"
属性,它的值是一个正整数,表示数组的长度;这个属性的特性是不可配置,不可枚举,因此它既不能被修改,也不能被删除。

2. 数组可以添加非正整数属性,但添加非正整数属性的操作并不会影响数组的"length"
属性值;只有添加正整数属性才会引起数组"length"
属性值的变化(删除也是一样)。

数组也可以不添加任何属性,就是我们常说的空数组,此时数组只有一个默认的"length"
属性。

3. 调用数组方法,只会操作其正整数属性,而忽略其他属性。

分析完数组之后,我们发现对于一个数组而言,只有"length"
属性是必须的。
实际上只要一个对象像数组一样拥有"length"
属性,且"length"
属性的值是一个正整数,我们就可以把它看作类数组对象。
我们可以用Array.from()
方法将一个可迭代对象或类数组对象转换成一个浅拷贝的数组。

如上图所示:
如果被转换的对象只指定了"length"
属性,转换后的数组会根据"length"
的值按顺序创建出指定数量的正整数属性,默认属性值都是undefined
;
如果如果被转换的对象指定了"length"
属性,且存在正整数属性,则转换后的数组会根据"length"
的值按顺序创建出指定数量的正整数属性,且匹配对象正整数属性的属性值,匹配不到的默认值是undefined
;
如果被转换的对象有非正整数属性,则这些属性会被忽略。
也可以对类数组对象调用数组的方法:

注意!因为类数组对象没有map()
方法,所以我们要从数组的原型对象中借用这个函数,并使用call()
方法,使它在arrLike
对象上调用。
字符串对象和函数中的arguments
也都是类数组对象,因为它们都有一个"length"
属性。

注意:字符串并不是类数组对象,因为它连对象都不是,只有字符串对象才能被称为类数组对象!
之所以字符串能够被转换成数组,是因为它在内部先被转换成了字符串对象,然后再被转换成了数组。

最后,结合我们对类数组对象的理解,来完成一个测试函数,用来测试对象是不是类数组对象:
function isArrayLike(x) {
if(
typeof x === "object" // 如果x是一个对象
&& x.length // 有一个"length"属性
&& Number.isInteger(x.length) // "length"属性的值是一个整数
&& x.length >= 0 // 大于或等于0
&& x.length < 4294967296 // 元素数小于4294967296(必须小于2的32次方)
) {
return true;
} else {
return false;
}
}