2

I have some javascript code that I am trying to clean up... I originally wrote the definition of an array of objects (called myData) in "brute force" style. The brute force style defines an array of 4 objects (array is always of size 4). My application works fine when defined this way. Code later in the program reads JSON and updates various elments in syntax similar to :

myData[2].Quarter = "Q2";

When I try to clean up/consolidate the definition of myData, my code runs without syntax error, but all 4 elements of the array end up with identical values, where in the brute force style, each object in the array end up with different values. The only thing that is different is the two definitions. This is what I call "brute force", and my entire code set works fine...It is literally the same object copied 4 times.

var myData = [
     {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    }   
    ];

I try to consolidate this down, to what I think should be identical code, but then my application no longer works. The symptom is that all 4 objects of the array end up with identical values.

Consolidated (but broken) code:

 var myDataStruct= {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    };

    var myData = [];
    myData.push(myDataStruct);
    myData.push(myDataStruct);
    myData.push(myDataStruct);
    myData.push(myDataStruct);

What am I doing wrong, and how can I define myData is a proper consolidated way?

2
  • 4
    Because objects are passed by reference in JS - so your array contains the same object in each index - updating 1 will update each of them. You'll need to clone your object into each index - search for that. Commented Aug 28, 2017 at 16:00
  • 1
    You added same reference to 4 indexes of array... When you change one of them you change them all Commented Aug 28, 2017 at 16:02

3 Answers 3

5

You may wanna use Object oriented programming and inheritance:

var myDataStruct = {
    Quarter: 'EMPTY',
    Field_Cloud:0,
    Field_Cloud_Renew:0,
    Field_On_Premise:0,
    Field_Total:0,
    OD_Cloud:0,
    OD_Cloud_Renew:0,
    OD_On_Premise:0,
    OD_Total:0,
    Field_OD_Total:0
};

var myData = Array.from({length:4}, ()=>Object.create(myDataStruct));

Or you clone that object, four times, like this ( bad for memory consumption, no real advantage):

var myData = Array.from({length:4}, ()=>Object.assign({},myDataStruct));

How they look like in memory:

1) your approach, pushing the same obj into the array:

//the object
123:
  {Quarter:"Empty",...}
//the array
124: 123
125: 123
126: 123
127: 123
128: null

2) the inheritance approach:

//the prototype
123:
  {Quarter:"empty",...}
//the subobjects
124:
  { prototype: 123}
125:
  { prototype: 123}
126:
  { prototype: 123}
127:
  { prototype: 123}
//the array
128:124
129:125
130:126
131:127
132: null

So with your approach, changing one of the array elems, actually changes the object stored at 123, so they interfer each other. With the inheritance approach, e.g. changing the first object changes the object at 124, on propertylookup, it will first search the property at 124, then if its not found itll search in 123. So if you do

myData[0].Quarter = "Full";

The memory will change to:

//the prototype
123:
  {Quarter:"empty",...}
//the subobjects
124:
  {Quarter: "Full", prototype: 123}

Which results in:

myData[0].Quarter // "Full", looked up in 124
myData[1].Quarter // "empty", as not found in 125 and therefore looked up in 123
Sign up to request clarification or add additional context in comments.

1 Comment

Worked beautifully. Thanks!
3

The problem is due to Javascript handling objects by reference.

If you create an object and push it to some array four times then there are four references to the same object in array. If you change the object afterwards, this change seems to affect all objects in array. But that's only due to array containing four references to one object, not four copies of one original object. If you need copies of your object added you need to create those copies first which isn't available in Javascript quite as straightforward as it is in other languages.

Just think of variables storing objects (which is including functions and arrays in Javascript for each being some more specific sort of object) as containing the address in memory where your object is stored. If you use that variable for accessing the object it is just pointing to some memory. If you assign the variable's value to some other variable or pass it as argument to some function such as the array's push() that address is copied and passed, not the properties of your object.

When it comes to copying/cloning objects there are more aspects to obey: if your object has properties of type object (or array or function) you might want to make copies of those as well. And they might have such properties in turn, too. So, do you need a shallow or a deep copy of your object? And objects might have properties you can access, but that aren't processed by some operations, but still you want them to be copied. This aspect affects enumerable vs. non-enumerable properties. Finally every object might have own properties and "derived" properties and some operations process all of them or just own properties of object.

So, take care of the approach you actually require to clone your object.

You might ask: why doesn't Javascript create copies implicitly? I think this is due to the language's simplicity in structure. And as soon as you take care of this "problem" you might realize how fast Javascript can be. I'd rather have to take care of this myself than suffering from a language wasting time with copying objects or implementing copy-on-write magic.

Examples

Deep Copy, Slow Performance, All Enumerable Properties

copy = JSON.parse( JSON.stringify( original ) );

Shallow Copy, Good Performance, Own Enumerable Properties

copy = Object.assign( {}, original );

more on objects

2 Comments

You might ask: why doesn't Javascript create copies implicitly? , cause if i do let current = users[0]; current.name = "Jack" , i want users[0] to change too...
Of course, you are right ... from a special intention's point of view. Guess there are other intentions benefitting from implicit copies, though. Eventually I love Javascript for its rough simplicity, when it comes to implementing the runtime or on making assumptions about how this will be handled by runtime most likely. (And for sure, this applies to other languages, too.)
0

You are pushing the same object reference into your array, which means that when you modify one object from your array, all of them are modified.

To fix this, you could use Object.assign() or the Object Spread syntax, like myData.push(Object.assign({}, myDataStruct));, which will create an empty object, merge it with your myDataStruct object and then push it into the array.

Useful links:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.