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

3

我有一个情况,需要创建一个从Array继承的新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

我在这里缺少什么?


非常有趣。我已经在JSBin上测试了你的代码,得到的长度等于3;但是当我尝试警告x [9]时,它确实返回存储的值“将[]直接指向9”。 - mamoo
如果您参考了“Ollie”的回复,似乎x[9]是指无序(简单关联)项。在x[9]中,x被视为字符串键'9'。如果您执行x ['9'],您也将收到“直接[]到9”的结果。 - Shamasis Bhattacharya
3个回答

4

5
也可以(非常新的、全面的):http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/ - Pointy
非常有趣的是,在您提供的这两篇文章中,很多人抱怨说子类化数组是浪费时间的,没有必要这样做。然而,我遇到了这样一种情况:我需要修改数组的原型以容纳有序元素,以便在子对象没有特定元素的情况下,可以从原型中返回该元素。因此,如果我坚持我所规划的架构,也需要对Array进行子类化。不幸的是,上述两种替代方法实际上会降低主要要求(性能)。感谢@budinov.com。 - Shamasis Bhattacharya

3
这是一个经常让人们困惑的问题。length属性仅适用于有序元素。您无法扩展数组,然后插入任意的非连续键并期望它能够工作。这是因为一旦扩展了数组,length属性与数组内容之间的关系就会被破坏。Pointy上面的链接非常好地解释了这一点。
为了证明这一点,请将以下内容添加到您的示例的末尾:
console.log(x[4]);

正如您所看到的,您的输入是正确的,只是它不是有序数组的一部分。

就像JavaScript中的其他所有内容一样,Array对象只是一个带有字符串键的关联数组。非数字、非连续的键被隐藏起来,让你误以为它是一个“真正”的数值索引数组。

这种奇怪的混合设计使得Array对象可以做一些奇怪而神奇的事情,比如在同一个对象中存储有序和无序信息。我并不是说这是一个好主意,我只是说这是可能的。

正如你现在已经注意到的那样,在迭代这样的结构时,非连续的键不会出现,这对于数组用于有序信息的一般用例是有意义的。当你想要获取键控信息时,它是没有用处的,甚至是无用的。我敢说,如果顺序不重要,你应该使用对象而不是数组。如果你需要有序和无序存储,请在对象的属性中存储一个数组。


我猜这就是JavaScript数组当前行为范式的完美解释。 - Shamasis Bhattacharya

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

您可以像这样扩展此原型:

http://codepen.io/dustinpoissant/pen/AXbjxm?editors=0011

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();

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