new Array() vs Object.create(Array.prototype)

11
一个天真的困惑:
var arr1 = new Array();
var arr2 = Object.create(Array.prototype);
//Inserting elements in "both arrays"
arr1[0] =0;
arr1[9] =9;
arr2[0] =0;
arr2[9] =9;
arr1.push(10);
arr2.push(10);
console.log(arr1.length); // prints 11
console.log(arr2.length); // prints 1

两个对象都继承了Array.prototype,但它们在使用[]操作符时的行为不同。为什么?


1
普通对象不像数组那样为您计算长度... - dandavis
4
创建数组的方式太糟糕了! - lukas.pukenis
3
使用Object.create创建的JavaScript数组并不是真正的数组。这个问题在ECMAScript 5中仍然存在,无法对数组进行子类化。有一些解决方案可以使自定义对象具有数组行为,但它们仍然不会被视为实际的数组。这种方法可能会破坏原生的方括号表示法和其他数组特性,因此需要小心处理。 - Aamir Afridi
1
可怜的 var arr = [] - Andy
1
当然,var arr = [] 是正确的方式,但这与问题无关。 - ferrito
显示剩余2条评论
2个回答

9
在第一种情况下,当您访问整数、非负属性(索引)时,创建一个维护length属性的数组对象。
在第二种情况下,您创建了一个继承Array原型的常规对象。在该对象上使用[]与任何对象相同,只是在其上设置常规属性。
var arr1 = new Array(); // or var arr1 = [];
arr1[0] = 0;
arr1['foo'] = 3;
// arr1 has a length of 1 because 0 is an array index and 'foo' is a regular property.

var arr2 = Object.create(Array.prototype);
arr2[0] = 0;
arr2['foo'] = 3;
// arr2 has a length of 0 because both 0 and 'foo' are regular properties.

ECMAScript 5语言规范描述了如何在第15.4节中维护length

数组对象对某些属性名称进行特殊处理。当且仅当ToString(ToUint32(P))等于P并且ToUint32(P)不等于2^(32−1)时,属性名称P(以字符串值的形式)是一个数组索引

[...]

具体来说,每当添加一个名称为数组索引的属性时,如果需要,length属性将更改为该数组索引的数字值加一;


谢谢Vache。我知道这一点,但在两种情况下,创建的对象都继承自Array.prototype。正如我在例子中所指出的,使用Object.create创建的对象上应用push方法会修改继承的属性length。而使用方括号的表示法则行为不同。 - ferrito
1
我的回答可能不够清晰。方括号表示法不是原型中的一种方法,它是访问Javascript属性的一种方式。在 Array对象中(请注意,仅从 Array 的原型继承不足以成为数组),括号的行为与规范中所解释的不同。现在 pushlength 在原型中,这就是为什么在常规对象上调用 push 仍然会维护 length 的原因。 - dee-see
完全同意您的评论。 - ferrito

-2

var arr1 = new Array(); 是实例化数组的正确方式。它与使用数组字面量相同:var arr1 = [];


OP 知道这个。他想知道为什么“正确”的方法和“错误”的方法表现不同。 - dee-see

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接