Copy a variable's value into another

JavascriptJquery

Javascript Problem Overview


I have a variable which has a JSON object as its value. I directly assign this variable to some other variable so that they share the same value. This is how it works:

var a = $('#some_hidden_var').val(),
    b = a;

This works and both have the same value. I use a mousemove event handler to update b through out my app. On a button click, I want to revert b to the original value, meaning the value stored in a.

$('#revert').on('click', function(e){
    b = a;
});

After this if I use the same mousemove event handler, it updates both a and b, when earlier it was updating only b as expected.

I'm stumped over this issue! What is wrong here?

Javascript Solutions


Solution 1 - Javascript

It's important to understand what the = operator in JavaScript does and does not do.

The = operator does not make a copy of the data.

The = operator creates a new reference to the same data.

After you run your original code:

var a = $('#some_hidden_var').val(),
    b = a;

a and b are now two different names for the same object.

Any change you make to the contents of this object will be seen identically whether you reference it through the a variable or the b variable. They are the same object.

So, when you later try to "revert" b to the original a object with this code:

b = a;

The code actually does nothing at all, because a and b are the exact same thing. The code is the same as if you'd written:

b = b;

which obviously won't do anything.

Why does your new code work?

b = { key1: a.key1, key2: a.key2 };

Here you are creating a brand new object with the {...} object literal. This new object is not the same as your old object. So you are now setting b as a reference to this new object, which does what you want.

To handle any arbitrary object, you can use an object cloning function such as the one listed in Armand's answer, or since you're using jQuery just use the $.extend() function. This function will make either a shallow copy or a deep copy of an object. (Don't confuse this with the $().clone() method which is for copying DOM elements, not objects.)

For a shallow copy:

b = $.extend( {}, a );

Or a deep copy:

b = $.extend( true, {}, a );

What's the difference between a shallow copy and a deep copy? A shallow copy is similar to your code that creates a new object with an object literal. It creates a new top-level object containing references to the same properties as the original object.

If your object contains only primitive types like numbers and strings, a deep copy and shallow copy will do exactly the same thing. But if your object contains other objects or arrays nested inside it, then a shallow copy doesn't copy those nested objects, it merely creates references to them. So you could have the same problem with nested objects that you had with your top-level object. For example, given this object:

var obj = {
    w: 123,
    x: {
        y: 456,
        z: 789
    }
};

If you do a shallow copy of that object, then the x property of your new object is the same x object from the original:

var copy = $.extend( {}, obj );
copy.w = 321;
copy.x.y = 654;

Now your objects will look like this:

// copy looks as expected
var copy = {
    w: 321,
    x: {
        y: 654,
        z: 789
    }
};

// But changing copy.x.y also changed obj.x.y!
var obj = {
    w: 123,  // changing copy.w didn't affect obj.w
    x: {
        y: 654,  // changing copy.x.y also changed obj.x.y
        z: 789
    }
};

You can avoid this with a deep copy. The deep copy recurses into every nested object and array (and Date in Armand's code) to make copies of those objects in the same way it made a copy of the top-level object. So changing copy.x.y wouldn't affect obj.x.y.

Short answer: If in doubt, you probably want a deep copy.

Solution 2 - Javascript

I found using JSON works but watch our for circular references

var newInstance = JSON.parse(JSON.stringify(firstInstance));

Solution 3 - Javascript

newVariable = originalVariable.valueOf();

for objects you can use, b = Object.assign({},a);

Solution 4 - Javascript

the question is already solved since quite a long time, but for future reference a possible solution is

b = a.slice(0);

Be careful, this works correctly only if a is a non-nested array of numbers and strings

Solution 5 - Javascript

The reason for this is simple. JavaScript uses refereces, so when you assign b = a you are assigning a reference to b thus when updating a you are also updating b

I found this on stackoverflow and will help prevent things like this in the future by just calling this method if you want to do a deep copy of an object.

function clone(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Solution 6 - Javascript

I do not understand why the answers are so complex. In Javascript, primitives (strings, numbers, etc) are passed by value, and copied. Objects, including arrays, are passed by reference. In any case, assignment of a new value or object reference to 'a' will not change 'b'. But changing the contents of 'a' will change the contents of 'b'.

var a = 'a'; var b = a; a = 'c'; // b === 'a'

var a = {a:'a'}; var b = a; a = {c:'c'}; // b === {a:'a'} and a = {c:'c'}

var a = {a:'a'}; var b = a; a.a = 'c'; // b.a === 'c' and a.a === 'c'

Paste any of the above lines (one at a time) into node or any browser javascript console. Then type any variable and the console will show it's value.

Solution 7 - Javascript

For strings or input values you could simply use this:

var a = $('#some_hidden_var').val(),
b = a.substr(0);

Solution 8 - Javascript

Most of the answers here are using built-in methods or using libraries/frameworks. This simple method should work fine:

function copy(x) {
    return JSON.parse( JSON.stringify(x) );
}

// Usage
var a = 'some';
var b = copy(a);
a += 'thing';

console.log(b); // "some"

var c = { x: 1 };
var d = copy(c);
c.x = 2;

console.log(d); // { x: 1 }

Solution 9 - Javascript

I solved it myself for the time being. The original value has only 2 sub-properties. I reformed a new object with the properties from a and then assigned it to b. Now my event handler updates only b, and my original a stays as it is.

var a = { key1: 'value1', key2: 'value2' },
    b = a;

$('#revert').on('click', function(e){
    //FAIL!
    b = a;

    //WIN
    b = { key1: a.key1, key2: a.key2 };
});

This works fine. I have not changed a single line anywhere in my code except for the above, and it works just how I wanted it to. So, trust me, nothing else was updating a.

Solution 10 - Javascript

A solution for AngularJS:

$scope.targetObject = angular.copy($scope.sourceObject)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRutwick GangurdeView Question on Stackoverflow
Solution 1 - JavascriptMichael GearyView Answer on Stackoverflow
Solution 2 - JavascriptkernowcodeView Answer on Stackoverflow
Solution 3 - JavascriptKishor PatilView Answer on Stackoverflow
Solution 4 - JavascriptmarcoshView Answer on Stackoverflow
Solution 5 - JavascriptArmandView Answer on Stackoverflow
Solution 6 - JavascriptTrenton D. AdamsView Answer on Stackoverflow
Solution 7 - JavascriptTimView Answer on Stackoverflow
Solution 8 - JavascriptLasse BrustadView Answer on Stackoverflow
Solution 9 - JavascriptRutwick GangurdeView Answer on Stackoverflow
Solution 10 - JavascripttonysepiaView Answer on Stackoverflow