1

JSFiddle

I want to loop through an object, perform some changes to each of it's properties, and then push those to an array. Each object property is pushed multiple times (in the JSFiddle, I've set it to push twice for simplicity). Each 'iteration' has a few of the properties different (JSFiddle shows only 1, i.e. the 'number').

However, it seems that all objects being pushed in a single loop cannot possess unique properties. I'm looking for a solution for this.

Sorry for my poor English, it's difficult to explain issue and it would be easier to see the JSFiddle.

Actual output:

[{ x: 1, number: 1 },  
{ x: 1, number: 1 },  
{ y: 2, number: 1 },  
{ y: 2, number: 1 },  
{ z: 3, number: 1 },  
{ z: 3, number: 1 }] 

Expected output:

[{ x: 1, number: 0 },
{ x: 1, number: 1 },
{ y: 2, number: 0 },
{ y: 2, number: 1 },
{ z: 3, number: 0 },
{ z: 3, number: 1 }]

Code:

var items = { 
  "a": {
    "x": 1
  },
  "b": {
    "y": 2
  },
  "c": {
    "z" : 3
  }
};

var something = [];

for ( var key in items ) {
  var item = items[key];
  if ( items.hasOwnProperty(key) ) {
    for ( var i = 0; i < 2; i++ ) {
      item.number = i;
      something.push(item);
    }
  }
}

console.log(something);
Namanyay Goel
  • 2,641
  • 3
  • 20
  • 26
  • 1
    You're pushing `item` as a reference. The 0th and 1st element are the same (and 2nd and 3rd, and 4th and 5th). You can copy them but this de-references the item. I don't know which solution you need. It depends on what you want to do with `something`. – Halcyon Mar 17 '15 at 15:47
  • de-referencing the item will not be a problem, I need a clone not the exact item in the array. How do I go about this? I haven't heard of referencing in JS vefore, do you have any links to some literature? Thank you very much! – Namanyay Goel Mar 17 '15 at 15:48
  • @Halcyon read up on referencing. Seems like JS only uses references when dealing with objects, weird. How does one copy an object if de-referencing is not an issue? Thanks! – Namanyay Goel Mar 17 '15 at 15:51
  • Cloning/copying is not straightforward in JavaScript, some objects can't be cloned. But, if your target object is just data (which it is in your case) it's quite simple. You can do: `var clone = JSON.parse(JSON.stringify(item);` – Halcyon Mar 17 '15 at 15:51
  • @Halcyon Hmm, seems like the JSFiddle still doesn't work :/ if it's no problem, can you have a look at http://jsfiddle.net/g0b1ge2t/2/ please? – Namanyay Goel Mar 17 '15 at 15:57
  • See: http://jsfiddle.net/g0b1ge2t/3/ you're sharing the copy over the loop, instead of making a fresh copy ever time. – Halcyon Mar 17 '15 at 15:59

1 Answers1

1

I'll explain by dry-running. In the below loop, we pick the first key which is "a" in your 'items' object. Now lets get inside the loop

    for ( var key in items ) {

      //key has been set to "a"

     var item = items[key]; 

     //item now "refers" to the object items["a"] which is {"x":1}

      if ( items.hasOwnProperty(key) ) {
        for ( var i = 0; i < 2; i++ ) {

          //in loop 1 item is referring to {"x":1}
          //in loop 2 item is referring to {"x":1,"number":0} (modified in first iteration)

          item.number = i;

         //in loop 1 item gets "number" property and object becomes {"x":1,"number":0} in memory
         //in loop 2 it will still modify the same object. Hence {"x":1,"number":0} becomes {"x":1,"number":1}


          something.push(item);
          //in loop1 reference to the object gets pushed.
          //in loop2 reference to the object gets pushed. 
          //both references (items) essentially point to same object.

        }
      }
    }

You would need to create a copy of your object rather than multiple references to get the expected output. In Javascript, cloning of object is not straight forward. You can refer this link How do I correctly clone a JavaScript object?

However a simple solution to your current code will be to create a clone function and use it without worrying about deep-cloning issues and prototype-inherited properties. Here's the modified code.

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}
var items = {
  "a": {
    "x": 1
  },
  "b": {
    "y": 2
  },
  "c": {
    "z" : 3
  }
};



var something = [];

for ( var key in items ) {
  var item = items[key];

  if ( items.hasOwnProperty(key) ) {
    for ( var i = 0; i < 2; i++ ) {
      var tempItem = clone(item);
      tempItem.number = i;
      something.push(tempItem);
    }
  }
}

console.log(something);

Upvote if you find it useful.

Community
  • 1
  • 1
BoltCoder
  • 194
  • 5