0

I have currently an object which contains a array on which I can iterate.

====== First Step =====

Iterate over an object's attribute instead of the object itself

I am wondering if there's a way to use :

const obj = new YMap();
obj.forEach(...);

instead of

const obj = new YMap();
obj.map.forEach();

EDIT : From VLAZ Comment, I can add this :

this.forEach = function(f) { this.maps.forEach(f);}

In my constructor so my forEach iterate over the maps attribute of my object and not over my object itself.

===== Second Step =====

Avoid forEach imbrication to parse an object attribute of type Array of Map/List/Array

By extends, if I add a little more complexity on my object so it doesn't have an array but an array of list, is there a way to do :

const obj = new YMap();
obj.forEach(...);

instead of

const obj = new YMap();
obj.maps.foreach( function(map) { 
    map.forEach( function(item) {
        ...
    }
});

To explain it differently, I wonder if there's a way that exist that allow me to have this data structure :

{
    maps : [
        [ 'A', 'B' ],
        [ 'C', 'D' ],
        [ 'E', 'F' ]
    ]
}

Where I could use the code :

 obj.forEach(function(item) { console.log(item) });

that would output :

A B C D E F

without having to iterate over the array of array and then iterate on the items of each array using an imbricated forEach

My object looks like the following :

function YMap() {
    this.maps = [new HashMap()];

    Object.defineProperty(YMap.prototype, 'length', {get: function() {
        ...
    }});
}

YMap.prototype.add = function() {...}

YMap.prototype.get = function() {...}

[...]

module.exports = YMap;
Grégory L
  • 430
  • 3
  • 15
  • 1
    `Object.keys()` + `Array.prototype.forEach()` – Yevgen Gorbunkov Mar 23 '21 at 11:22
  • You can use `obj.forEach(...);` it you define it on your object. There is no way to automatically make that method available *and* do what you want it to do (iterate over `this.maps`?). What is `obj.map`? – VLAZ Mar 23 '21 at 11:25
  • @YevgenGorbunkov I think OP wants to iterate only over one attribute, not all. – VLAZ Mar 23 '21 at 11:26
  • You can define an iterator method and use a for..of loop: https://stackoverflow.com/questions/28739745/how-to-make-an-iterator-out-of-an-es6-class – Ivar Mar 23 '21 at 11:28
  • @VLAZ Yes indeed, I'm wondering here if I can add a shortcut that implictly use my forEach on an attribute instead of having to use myObj.attr.forEach(...) – Grégory L Mar 23 '21 at 11:28
  • Why is `Object.defineProperty(YMap.prototype,...` inside the constructor? – adiga Mar 23 '21 at 11:32
  • @adiga It felts wrong for me to put it out of nowhere. Do you mean that I could put it outside the constructor and still have it work as intented ? – Grégory L Mar 23 '21 at 11:34
  • Why not just define `this.forEach = function(f) { this.maps.forEach(f); }`? You can abstract it away and make it more of a mixin but is that really what you're after? – VLAZ Mar 23 '21 at 11:42
  • @VLAZ Thats a first part of the question yes. First step I wondered if I can use obj.forEach() instead of obj.maps.forEach(). Thanks ! The second step is that I wonder if I can avoid the use of double forEach to parse each item of each map. I'll edit my post for more clarity. – Grégory L Mar 23 '21 at 11:49
  • Avoid it how? You still need to iterate over every entry of `maps` and each of their entries. You can "avoid" `.forEach` by using another equivalent of it, like a regular loop. But that's basically the same thing anyway. I'm not sure what you expect to happen here. – VLAZ Mar 23 '21 at 11:52
  • I'm not saying it's possible, I was just wondering if someone had knowledge of some things that can make it possible to have a unique foreach that iterate over each item content one after another. Actually a "No that's not possible" is a totally valid answer for me. Just wondering. ^^ – Grégory L Mar 23 '21 at 11:56
  • If you want to call each `forEach` one after another, that's *just* nested iteration. [Like this](https://jsbin.com/poyikir/1/edit?js,console). I still don't understand how you expect to have this but without doing this (or equivalent?). – VLAZ Mar 23 '21 at 11:59
  • That's the point, I was just curious to know if I could make my object forEach acting like a nested iteration without having to do it. (Yeah that's strange, I understand) Like I could do something that iterate over the first item, the second one and so on without implementing myself an iterator so that when people use my object.forEach() it transparently iterate over each subobject one after another. – Grégory L Mar 23 '21 at 12:04
  • RE: latest edit: no. You cannot have code that goes over every item of every array, without having code that goes over every item in every array. Even if you do `this.maps.flat().forEach()` that's going to do fundamentally the same operation - go over every array (`.flat()`) go over each item `.forEach()`. You can, at best *hide* it (so, not an explicit nested loop) but you cannot avoid the operation. – VLAZ Mar 23 '21 at 12:05
  • You touch the point I had difficulties to explain : I want to hide it inside my object, not avoid the operation ! – Grégory L Mar 23 '21 at 12:09
  • OK, but hide it *how*? What is bad about a nested iteration? Why should it be hidden? Without this, I'm not sure what solution to give you. – VLAZ Mar 23 '21 at 12:10
  • @VLAZ I was wondering this because this object is used in some very complex parts of a project and so we have a lot of imbricated loops and I wanted to maybe have a look at how I could make it more readable when used. – Grégory L Mar 23 '21 at 12:23
  • [Would you consider this more readable?](https://jsbin.com/ranayeg/1/edit?js,console) I am not really sure myself. I personally might use it but I think nested iteration is perfectly fine. I can't really see how a developer who has trouble reading nested iteration will have better luck with alternatives. Besides, the reason to encapsulate the functionality in a method is to *spare the details*. If anybody just calls `obj.forEach()` they just need to know that the method will go over every entry of every item. They shouldn't bother with the *how* of it. – VLAZ Mar 23 '21 at 12:26

1 Answers1

0

you can create custom iterable to loop onto object. I have created one using class based approach with help of Symbol.iterator property.

class YMap {
  constructor() {
    this.maps = [];
  }

  [Symbol.iterator]() {
    let index = 0;
    const that = this;
    return {
      next() {
        let value = undefined;
        let done = true;
        if (index < that.maps.length) {
          value = [...that.maps[index++]].join(" ")
          done = false;
        }
        return {
          value,
          done
        };
      }
    };
  }
  add(item) {
    this.maps.push(item);
  }
}

const obj = new YMap();
obj.add([23, 21]);
obj.add([25, 29]);
for (let c of obj) {
  console.log(c, );
}
deepak
  • 1,174
  • 1
  • 7
  • 11