KunLun
KunLun

Reputation: 3225

Values from last FOR loop over all, after FOR is done

I have a function which get a json as parameter, build another json with some values from given json and return builded json.

function getMyJSON(json) {
  var result = {
    lastUpdate: "",
    legends: null
  };

  result.legends = (new Array(json.legends.length)).fill({
    name: null,
    rgb: null,
    values: null
  });

  for (let j = 0; j < json.legends.length; j++) {
    result.legends[j].name = json.legends[j].name;
    result.legends[j].rgb = json.legends[j].rgb;
    result.legends[j].values = (new Array(10)).fill(0);
    console.log(result.legends[0].name); //PRINT ONLY FIRST ELEMENT
  }

  console.log(result.legends);

  return result;
}

The problem appear after for loop is done. All result.legends have the same value from the last json.legends

Here is how output look:

enter image description here

The legends.name of first element(result.legends[0].name) is changed after every loop.

At the end, all legends.name from result are equal with the last legends.name from json. Why?

I found on google that it is something about variable scope, but I can't figure it out how to do this.

Upvotes: 1

Views: 46

Answers (2)

Rory McCrossan
Rory McCrossan

Reputation: 337560

@NinaScholz has described the problem and solved it, however as I mentioned in the comments on the question you can improve and simplify the logic by using map():

var obj = {
  legends: [{
    name: 'foo',
    rgb: 'C00'
  },{
    name: 'bar',
    rgb: 'FFF'
  },{
    name: 'fizz',
    rgb: 'CCFFCC'
  },{
    name: 'buzz',
    rgb: '000000'
  }]
}
console.log(getMyJSON(obj));

function getMyJSON(o) {
  return {
    lastUpdate: "",
    legends: o.legends.map(function(item) {
      return {
        name: item.name,
        rgb: item.rgb,
        values: (new Array(10)).fill(0)
      }
    })
  };
}

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386560

You need independent objects inside of the array. Array#fill takes the same object reference and this leads to the same result in each object.

Instead of this, you could create a new array with Array.from and map new objects with the second parameter for a callback.

result.legends = Array.from(
    { length: json.legends.length },
    _ => ({ name: null, rgb: null, values: null })
);

Upvotes: 2

Related Questions