Search code examples
javascriptarraysobjectfor-in-loop

JS Object created with for/in returning the same object to the array multiple times


I have an object data looks like this:

{
    "Meta Data": {
        "1. Information": "Intraday (5min) open, high, low, close prices and volume",
        "2. Symbol": "IBM",
        "3. Last Refreshed": "2021-09-09 18:05:00",
        "4. Interval": "5min",
        "5. Output Size": "Compact",
        "6. Time Zone": "US/Eastern"
    },
    "Time Series (5min)": {
        "2021-09-09 18:05:00": {
            "1. open": "137.8300",
            "2. high": "137.8300",
            "3. low": "137.8300",
            "4. close": "137.8300",
            "5. volume": "104"
        },
        "2021-09-09 17:25:00": {
            "1. open": "137.7500",
            "2. high": "137.7500",
            "3. low": "137.7500",
            "4. close": "137.7500",
            "5. volume": "478"
        },
        "2021-09-09 16:30:00": {
            "1. open": "137.8000",
            "2. high": "137.8000",
            "3. low": "137.8000",
            "4. close": "137.8000",
            "5. volume": "459"
        },
    }
}

Here is my function:

const myfunction = () => {
  var newArray = []
  var newObject = {}
  var firstobj = myobject['Time Series (5min)']

  for (var key in firstobj) {
    console.log(key)
    newObject.x = key.substr(11, 19)
    newObject.y = myobject['Time Series (5min)'][`${key}`]['4. close']

    newArray.push(newObject)
  }
  return newArray
}

console.log(myfunction())

JS Object created with for/in returning the same object to the array multiple times. I am not sure why I cant see the bug, or where I am going wrong. Does anybody know how I am supposed to be returning the object to the newArray so that it creates a list of {x: 1234, y: 1234}. (just example numbers, see image attached to this view code / console together. The first part of the console is the end of the logged keys, and the 2nd part of the console is the start of the log for the array of objects, [{x: 1234, y: 1234}, {x: 1234, y: 1234}] I would like to return!

Result needs to be:

[{ x: '15:50:00', y: '138.3550' },
 { x: '15:55:00', y: '134.3250' }]

not:

[{ x: '15:50:00', y: '138.3550' },
 { x: '15:50:00', y: '138.3550' }]

PS: I have returned the structure as an array, but not as an array of objects. I just wanted to say that I am calling the API correctly, just maybe not referencing it properly.

PPS: If there is a much simpler way to do this, please let me know what you would do!


Solution

  • You push your newArray full with references to the same object.

    const obj = { x: 0, y: 0 };
    const newArray = [obj];
    
    obj.x = 1;
    newArray.push(obj);
    
    // since index 0 and 1 refer to the same object they will now "both" be
    // { x: 1, y: 0 }
    

    So instead of using a single object, create a copy and then update the properties:

    for (var key in firstobj) {
      console.log(key)
      const copy = { ...newObject }; // create a shallow copy
    
      // Setting x and y don't update newObject, and objects pushed to
      // newArray are distinct objects.
      copy.x = key.substr(11, 19)
      copy.y = myobject['Time Series (5min)'][`${key}`]['4. close']
    
      newArray.push(copy)
    }