最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - create an ES6 class with Array like behaviour - Stack Overflow

matteradmin7PV0评论

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.

Post a comment

comment list (0)

  1. No comments so far