0

According to this answer I want to create my own subclass of Array

QArray = function() {
    Array.apply(this, arguments);
};
QArray.prototype = new Array();
QArray.prototype.constructor = QArray;

which works as expected, method invocation works, but the constructor does not chain to Array.

// test constructor chaining
q = new QArray('1', '2', '3');
assert.equals('1', q[0]);      // => undefined
assert.equals(3, q.length);    // => 0
q = new QArray(10);
assert.equals(10, q.length);   // => 0

This tests pass if I replace QArray with plain Array. Somehow Array seems to be a special case. (I run this in Rhino 1.6 which is Javascript 1.5.) How can I fix my custom subclass of Array?

Community
  • 1
  • 1
Peter Kofler
  • 9,252
  • 8
  • 51
  • 79

1 Answers1

1

Since your method already inherits the array methods, you can use array methods which modify the keys, such as Array.prototype.push:

QArray = function() {
    if (arguments.length == 1) this.length = arguments[0]; // Array constructor
    else this.push.apply(this, arguments);
};
QArray.prototype = new Array();
QArray.prototype.constructor = QArray;

q = new QArray('1', '2', '3');   // => [1,2,3]
assert.equals('1', q[0]);        // => true
assert.equals(3, q.length);      // => true
q = new QArray(10);              // => [,,,,,,,,,]
assert.equals(10, q.length);     // => true
q instanceof QArray;             // => true
q instanceof Array;              // => true

I've once written a custom array implementation, which behaves like a true array (including length setter/getter). If you need inspiration, have a look at this answer.

Community
  • 1
  • 1
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • Thank you. Yes I could reimplement the `Array.prototype.constructor` logic. But why do I have to? – Peter Kofler Jun 15 '12 at 21:51
  • @PeterKofler Because the Array constructor does not modify the array, but creates and returns new one: `var a = [];Array.call(a) == a;` (false), opposed to `var a=[];Array.prototype.reverse.call(a)==a;` (true). – Rob W Jun 15 '12 at 22:04
  • Thank you. This works with the constructor. All array methods work **but** `q = new QArray(); q[3] = 'mango'; q.length // => 0 instead of 4`, so the length is not updated when a new element is set with `q[]` directly. – Peter Kofler Jun 16 '12 at 22:22
  • @PeterKofler Length is a special property. If the length getter/setter is very important to you, see the answer which I've linked. – Rob W Jun 18 '12 at 21:35