什么是类数组对象

类数组对象的特点介于对象和数组之间:

  • 类数组对象是一个对象,而不是数组;
  • 虽然类数组对象是一个对象,却可以在它上面调用数组方法来操作它的正整数属性。

在深入了解类数组对象之前,我们先来分析一下数组。

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;
    }
}