curveball
curveball

Reputation: 4505

Symbol.iterator: get all the object's properties in iterator object

I am currently reading about Symbols and Iterators (ES6 features) and after running into an example there, I am trying to make an object iterable so that I can use for...of feature. From few examples/answers here/articles I checked, it looks like this in plain case:

let obj = {
  prop1: 5,
  prop2: 'test',
  prop3: new Date(),
  [Symbol.iterator]: () => ({
  items: obj.items,
  next: function next() {
    return {
        done: this.items.length === 0,
        value: this.items.shift()
      }
  }
  })
};
Object.defineProperty(obj, "items", {
  enumerable: false,
  get: function() {
      let props = [];
      for(let prop in this) if(this.hasOwnProperty(prop)) props.push(this[prop]);
      return props;
  }
});
for(let prop of obj) console.log(prop);

But I find it annoying to list manually all the values of an object's properties in items array of iterator. Also it feels dirty and messy with Object.defineProperty. I am kind of trying tom expand the example from the link. Is there a smarter/simpler way to get all the object's properties inside iterator (instead of items: obj.items and related bloat or manually listing items like items: [5, 'test', new Date()])?

Upvotes: 0

Views: 3291

Answers (3)

zloctb
zloctb

Reputation: 11177

function objectEntries(obj) {
    let index = 0;

    // In ES6, you can use strings or symbols as property keys,
    // Reflect.ownKeys() retrieves both
    let propKeys = Reflect.ownKeys(obj);

    return {
        [Symbol.iterator]() {
            return this;
        },
        next() {
            if (index < propKeys.length) {
                let key = propKeys[index];
                index++;
                return { value: [key, obj[key]] };
            } else {
                return { done: true };
            }
        }
    };
}

let obj = { first: 'Jane', last: 'Doe' };
for (let [key,value] of objectEntries(obj)) {
    console.log(`${key}: ${value}`);
}

http://2ality.com/2015/02/es6-iteration.html

Upvotes: 1

Bergi
Bergi

Reputation: 664494

You should not use an items getter but instead just create the array inside the iterator method. Also you can use generator syntax to create the iterator, which is much easier.

But the simplest way to achieve what you want is

let obj = {
  prop1: 5,
  prop2: 'test',
  prop3: new Date(),
  [Symbol.iterator]() { return Object.keys(this).map(k => this[k])[Symbol.iterator](); }
};

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138267

You could return a generator in the symbol iterator maybe:

[Symbol.iterator]:function*(){
    for(value of Object.values(this)){
      yield value;//may extend this to your needs
    }
 }

Or in your case:

[Symbol.iterator]:function*(){
  var i=1;
  while(this["prop"+i]){
      yield this["prop"+i];//may extend this to your needs
      i++;
  }
}

http://jsbin.com/zekunalusi/edit?console

Upvotes: 3

Related Questions