BrunoLM
BrunoLM

Reputation: 100322

How to make a class behave like an array?

I know I could create my own Number class by overriding valueOf

function MyNumber(n)
{
    this.n = n;
}

MyNumber.prototype.valueOf = function() { return this.n; };

Then I could do this:

var n = new MyNumber(10);

console.log(n + 1); // 11

I want to know how I could access each value by index, like this

function MyArray(a)
{
    this.a = a;
}

MyArray.prototype.valueOf = function() { return this.a; };

var a = new MyArray([1, 2, 3]);

console.log(a[0])

Is it possible? How?

Upvotes: 3

Views: 463

Answers (3)

forresto
forresto

Reputation: 12388

You can do it by returning a Proxy from your constructor.

class ArrayLike {
  data = [];

  constructor(...args) {
    this.data.push(...args)

    return new Proxy(this, {
      get: function(target, prop, receiver) {
        const n = +prop;

        // Number access works like array index
        if (!isNaN(n)) {
          return target.data[n];
        }

        // Other access passes through
        return Reflect.get(target, prop, receiver);
      }
    });
  }

  get length() {
    return this.data.length;
  }
}

const notArray = new ArrayLike("a", "b", "c");
console.log(notArray[0])
console.log(notArray[1])
console.log(notArray.length)

This class in this example won't have the other array methods.

The answer to another question shows a way to extend the native Array, and make negative indices return from the end of the array.

Upvotes: 0

cwallenpoole
cwallenpoole

Reputation: 81988

That's as simple as a for... in loop:

function MyArray(a)
{
    this.a = a;
    for(var it in a) this[it] = a[it];
}

Actually, jQuery does something very much like this which is why you can do something like $('body')[0] and get the body tag. The jQuery object, when it has received the return of the seletor query, goes through each of those indexes and maps it to this[i] = <selected node>. And while Arrays do have a special length property, that type of assignment will get you most of the way there.

Upvotes: 4

Amadan
Amadan

Reputation: 198324

You can't overload indexing operator (or any operator) in JavaScript.

You could imitate it by making MyArray constructor copy a[i] to this[i], but you won't get the magic of length.

Upvotes: 4

Related Questions