Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

create an ES6 class with Array like behaviour

I am trying to create a class that behaves a bit like an array. There are two things that I would like to have:

  • has to be iterable
  • should allow for property accessing via [index] where index is an integer

Making a class iterable is fairly easy:

class MyList {
    constructor() {
        this._list = [1, 2, 3];
    }
    [Symbol.iterator]() {
        return this._list.values();
    }
}

The above allows an instance of the class to be iterated over:

let myList = new MyList();
for (let item of myList) {
    console.log(item); // prints out 1, 2, 3
}

Figuring out how to implement the second requirement turns out it's not as easy and the only think I found would be to extend Array. But this means that I would have to override most of the methods inherited from Array as I would need those methods to do something else than the built in behaviour.

Is there a way to achieve what I am asking? If so, what would be the best approach to do it?

like image 940
Roland Avatar asked Oct 10 '15 16:10

Roland


1 Answers

Turns out you can store properties under integer-like string keys, e. g. foo['0'] = 'bar' and access them with integers, e. g. foo[0] // => bar. Assigning with an integer also works. Thanks to @JMM for pointing this stuff out.

Thus, the solution is as simple as:

class Foo {
  constructor (...args) {
    for (let i = 0; i < args.length; i++) {
      this[i] = args[i];
    }
  }

  [Symbol.iterator]() {
    return Object
      .keys(this)
      .map(key => this[key])
      .values();
  }
}

const foo = new Foo('a', 'b', 'c');

for (let item of foo) {
  console.log(item); // prints out a, b, c
}

console.log(foo[1]); // prints out b

Demo.

like image 137
Andrey Mikhaylov - lolmaus Avatar answered Sep 28 '22 06:09

Andrey Mikhaylov - lolmaus