【问题标题】:JavaScript - Difference between Array and Array-like objectJavaScript - 数组和类数组对象之间的区别
【发布时间】:2015-06-24 19:10:05
【问题描述】:

我在 JavaScript 中经常遇到“类数组对象”这个术语。它是什么?它和普通数组有什么区别?类数组对象和普通对象有什么区别?

【问题讨论】:

  • 一个是数组,另一个是对象。一个有数组方法,另一个可能有也可能没有。
  • 类数组对象是一个对象,您可以使用常规 for 循环和数字索引对其进行迭代。许多原生 DOM 方法(如 getElementsByClassName())返回类似数组的对象。
  • 这就像狗和类似狗的动物之间的区别,但是如果您不知道“喜欢”是什么意思,那是无用的解释。
  • 我认为这不是一个糟糕的问题。例如,“类数组”也可能意味着该对象公开了一个 forEach 方法(这并不意味着)。澄清哪些特征使对象类似于数组是好的:)
  • 为什么这个问题被否决了?

标签: javascript arrays


【解决方案1】:

首先,数组是一个专门的对象。擅长:

  • 有一个特殊的文字语法[ … ]
  • 有一个length 属性会自动更新
  • 数组原型包括您通常期望从数组中获得的函数

另一个明显的特点是所有元素都有一个数字索引。

从 JavaScript 的角度来看,任何具有 length 属性的对象都足够接近,可以被视为类似数组的对象:

var arrayLikeObject = {
    length: 3,
    name: 'thing',
    '1': 'hello'
};
console.log(arrayLikeObject);

length 属性不必是正确的。即使在普通数组中,也可以强制 length 不同于实际元素的数量。缺失的元素全部返回undefined

您可以使用Array.from() 将类数组对象转换为真实数组。此函数将采用各种值,但最简单的是:

var arrayLikeObject = {
    length: 3,
    name: 'thing',
    '1': 'hello'
};
var array = Array.from(arrayLikeObject);
console.log(array);

从这里开始,数组具有所有常用的属性和方法。在上面的示例中,属性[1] 被复制到新数组中,但元素[name] 没有,因为它不属于真正的数组。

Array.from() 函数还接受映射函数作为第二个参数。这使您可以在运输过程中进行任何需要的更改:

var arrayLikeObject = {
    length: 3,
    name: 'thing',
    '1': 'hello'
};
var array = Array.from(arrayLikeObject,
    (element,index) => element?element.toUpperCase():`Item ${index}`
);
console.log(array);

【讨论】:

    【解决方案2】:

    还有性能差异。在这个video Mathias Bynens 建议使用数组而不是类数组对象,因为 V8 针对常见数组进行了优化。

    【讨论】:

      【解决方案3】:

      著名的HTMLCollection (documentation) 和arguments (documentation) 是自动创建的类数组对象。

      真实数组示例之间的一些类似数组(例如HTMLCollection)的快速差异:

      var realArray = ['value1', 'value2'];
      var arrayLike = document.forms; 
      

      相似之处:

      长度getter是一样的:

      arrayLike.length; // returns 2;
      realArray.length; // returns 2; //there are 2 forms in the DOM.
      

      索引的getter是一样的:

      arrayLike[0]; // returns an element.
      realArray[0]; // returns an element. ('value')
      

      他们都是objects:

      typeof arrayLike; // returns "object"
      typeof realArray; // returns "object"
      

      区别:

      join()concat()includes() 等数组中,方法不是函数:

      arrayLike.join(", "); // returns Uncaught TypeError: arrayLike.join is not a function (also relevant to `concat()`, `includes()` etc.)
      realArray.join(", "); // returns "value1, value2"
      

      数组 like 并不是真正的数组:

      Array.isArray(arrayLike); //returns "false"
      Array.isArray(realArray); //returns "true"
      

      在数组中无法设置长度属性:

      arrayLike.length = 1;
      arrayLike.length; //return 2; //there are 2 forms in the DOM.
      realArray.length = 1;
      realArray.length; //return 1;
      

      【讨论】:

        【解决方案4】:

        我认为,在 ES6 中,如果它是可迭代的(具有 [Symbol.iterator] 属性),则它类似于数组。

        【讨论】:

        • 'Array-like object' 是对存在的事物的实际标题。它定义了可以具体应用于以特定方式构建和使用的对象的属性。
        • 你认为还是你知道?根据这篇文章dmitripavlutin.com/javascript-array-from-applications 中的声明,您可能是对的 -> 此外,您可以将 Array.from() 与任何实现可迭代协议的对象或原语一起使用
        • 没有。 { length: 5} 是一个类数组对象,但不是可迭代对象。
        【解决方案5】:

        这是什么?

        一个 Object,它具有非负 Integerlength 属性,通常还有一些索引属性。例如

        var ao1 = {length: 0},                     // like []
            ao2 = {0: 'foo', 5: 'bar', length: 6}; // like ["foo", undefined × 4, "bar"]
        

        您可以使用 Array.prototype.slice

        类似数组的对象 转换为对应的 数组
        var arr = Array.prototype.slice.call(ao1); // []
        

        它和普通数组有什么区别?

        它不是由Array数组字面量 [] 构造的,因此(通常)不会从​​Array.prototype 继承。 length 属性通常也不会自动更新。

        ao1 instanceof Array; // false
        ao1[0] = 'foo';
        ao1.length; // 0, did not update automatically
        

        类数组对象和普通对象有什么区别?

        没有区别。即使是普通的 ArraysJavaScript

        中也是 Objects
        ao1 instanceof Object; // true
        [] instanceof Object; // true
        

        【讨论】:

        • and so (usually) won't inherit from Array.prototype 想详细说明“通常”部分吗?如果它继承自Array.prototype,它不是类似于数组而是数组?
        • @Taurus 如果你用 ES5 方式为一些自定义对象设置原型,你会得到类似数组的Array.isArray(Object.create(Array.prototype)); // false。如果你使用 ES6+ class A2 extends Arraysuper,你会得到 Arrays Array.isArray(new A2); // true
        • @Paul_S。我认为这更像是 isArray 方法的一个陷阱,因为它在幕后使用了内部的 [[class]] 属性,而不是证明带有 Array.prototype 的对象是类似数组的对象,而是具有它可用的数组方法(通过从Array.prototype 继承,这也意味着它具有length 属性)并且数字索引不是类似数组,它是一个数组。
        • @Taurus 在 ES5- 版本中,即使你做了类似function Foo() {}; Foo.prototype = Object.create(Array.prototype); f = new Foo; 的操作,请考虑f[0] = 1; f.length; // => 0。这意味着它不是真正的数组,因为设置索引不会对长度产生预期的副作用。对 ES6+ 做同样的事情确实会对长度产生副作用
        • @techie_28 添加一个 length 并且它会排序,没有 length 你的对象不是 Array-like
        猜你喜欢
        • 2019-11-01
        • 2023-03-23
        • 2018-03-15
        • 1970-01-01
        • 2011-12-09
        • 1970-01-01
        • 1970-01-01
        • 2015-05-08
        • 1970-01-01
        相关资源
        最近更新 更多