admin管理员组

文章数量:1435557

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?

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?

Share Improve this question edited Oct 10, 2015 at 16:14 Roland asked Oct 10, 2015 at 16:04 RolandRoland 9,73919 gold badges82 silver badges136 bronze badges 14
  • Is it required that a var test = MyList(); test[2] = 1; results in a [undefined, undefined, 2] with a test.length of 3? Or is it only important, that the data is accessible by [] ? – t.niese Commented Oct 10, 2015 at 16:09
  • @t.niese I guess not, I haven't thought about that :) – Roland Commented Oct 10, 2015 at 16:11
  • 1 Why do you use _list to store the data, instead of storing it directly with the object: this[idx] = 2 instead of this._list[idx] = 2. Is there a reason why you don't want to do that? – t.niese Commented Oct 10, 2015 at 16:15
  • @t.niese hmmm, that is actually a good question. It was just an example and it was how I had the implementation before, I stored the values on a private property (I am doing with Typescript, I realize that there are no private properties at this point in JS). But I think it should be fine to store it directly on the class. – Roland Commented Oct 10, 2015 at 16:21
  • 1 Sounds like you need a Proxy to intercept assignments. – Bergi Commented Oct 11, 2015 at 18:21
 |  Show 9 more ments

1 Answer 1

Reset to default 8

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.

本文标签: javascriptcreate an ES6 class with Array like behaviourStack Overflow