在JavaScript中,如何使用[]运算符访问从数组继承的对象?

在JavaScript中,如何使用[]运算符访问从数组继承的对象?,javascript,prototype,prototypal-inheritance,Javascript,Prototype,Prototypal Inheritance,有一种情况,我需要创建一个从数组继承的新JavaScript对象。我正在使用以下代码: // Create constructor function. var SpecialArray = function () {}; // Create intermediate function to create closure upon Array's prototype. // This prevents littering of native Array's prototype. var ISpe

有一种情况,我需要创建一个从数组继承的新JavaScript对象。我正在使用以下代码:

// Create constructor function.
var SpecialArray = function () {};

// Create intermediate function to create closure upon Array's prototype.
// This prevents littering of native Array's prototype.
var ISpecialArray = function () {};
ISpecialArray.prototype = Array.prototype;
SpecialArray.prototype = new ISpecialArray();
SpecialArray.prototype.constructor = SpecialArray;


// Use Array's push() method to add two elements to the prototype itself.
SpecialArray.prototype.push('pushed proto 0', 'pushed proto 1');

// Use [] operator to add item to 4th position
SpecialArray.prototype[4] = 'direct [] proto to 4';

// Create new instance of Special Array
var x = new SpecialArray();

// Directly add items to this new instance.
x.push('pushed directly on X');
x[9] = 'direct [] to 9'

console.log(x, 'length: ' + x.length);
非常有趣的是,[]操作似乎毫无用处,控制台输出是:

["pushed proto 0", "pushed proto 1", "pushed directly on X"] length: 3

我在这里错过了什么?

这是一个总是让人绊倒的问题。length属性仅适用于有序元素。您不能扩展一个数组,然后插入一个任意的非顺序键并期望它工作。这是因为一旦扩展数组,length属性和数组内容之间的关系就会中断。上面的Pointy链接非常详细地解释了这一点

要证明这一点,请在示例末尾添加以下内容:

console.log(x[4]);
正如您所看到的,您的条目是存在且正确的,它不是有序数组的一部分

与javascript中的其他内容一样,数组对象只是一个带有字符串键的关联数组。隐藏非数字、非顺序键,以欺骗您认为它是一个“正确”的数字索引数组

数组对象的这种奇怪的混合设计确实意味着您可以在同一个对象中存储有序和无序的信息。我不是说这是个好主意,我只是说这是可能的


正如您现在已经注意到的,当迭代这样的结构时,非顺序键不会出现,这对于有序信息的数组的一般用例来说是有意义的。当你想获得关键信息时,它就没那么有用了,或者说实际上是无用的。我敢说,如果排序不重要,那么应该使用对象而不是数组。如果同时需要有序和无序,则将数组作为属性存储在对象中。

不可能对数组类进行子类化并以这种方式使用t。 对您来说,最好的解决方案是只扩展array类并按原样使用它。 我不喜欢另外两种选择,但它们是存在的


我发现创建“数组”子原型的最佳方法是不要创建“数组”的子原型,而是创建“类似数组”原型的子原型。有许多原型试图模仿“数组”的属性,同时仍然能够从中“继承”,我发现最好的原型是因为它保留了使用括号的能力
[]
。主要的缺点是它不能很好地使用非数字键(即
myArray[“foo”]=“bar”
),但如果您只使用数字键,它的效果会很好

您可以这样扩展此原型:


很有趣。我已经用JSBin测试了你的代码,我得到的长度等于3;无论如何,当我试图提醒x[9]时,它确实会返回存储值“direct[]to 9”。@mamoo:如果您使用“Ollie”来引用响应,那么x[9]似乎是指无序(简单关联)项。在x[9]中,x被视为字符串键“9”。如果你做了x['9'],你也会收到“direct[]to 9”。还有(最近的,彻底的):非常有趣的是,在你链接的上述两篇文章中,很多人抱怨说这对子类数组是一种浪费,没有必要这样做。然而,我有一种情况,我需要修改数组的原型以保存有序元素,这样,如果子对象没有特定的元素,它将从原型返回。所以,如果我坚持我计划的体系结构,子类化数组也是必需的。可悲的是,在上述两种交替攻击中,主要需求(性能)实际上已经降低。谢谢@budinov.com我想这是当前JavaScript数组行为范式的完美推理。
var MySubArray = function(){
  Collection.apply(this, arguments);
  this.myCustomMethod = function(){
    console.log("The second item is "+this[1]);
  };
};
MySubArray.prototype = Object.create(Collection.prototype);

var msa = new MySubArray("Hello", "World");
msa[2] = "Third Item";
console.log(msa);
msa.myCustomMethod();