将变量的值复制到另一个变量中

时间:2013-09-16 13:21:59

标签: javascript jquery

我有一个变量,它有一个JSON对象作为其值。我直接将此变量分配给其他变量,以便它们共享相同的值。这是它的工作原理:

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

这有效,两者都有相同的价值。我使用mousemove事件处理程序通过我的应用程序更新b。点击按钮,我想将b恢复为原始值,即a中存储的值。

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

在此之后如果我使用相同的mousemove事件处理程序,它会同时更新ab,之前它只按预期更新b

我很难过这个问题!这有什么不对?

10 个答案:

答案 0 :(得分:171)

了解JavaScript中的=运算符执行和不执行的操作非常重要。

=运算符未对数据进行复制

=运算符为相同的数据创建新的引用

运行原始代码后:

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

ab现在是同一个对象的两个不同名称

无论是通过a变量还是b变量引用,您对此对象内容所做的任何更改都将完全相同。它们是同一个对象。

因此,当您稍后尝试使用此代码将b“还原”到原始a对象时:

b = a;

代码实际上什么都没有,因为ab完全相同。代码与您编写的代码相同:

b = b;

显然不会做任何事情。

为什么新代码有效?

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

在这里,您要使用{...}对象文字创建一个全新的对象。这个新对象与旧对象不同。因此,您现在将b设置为对此新对象的引用,该对象可以执行您想要的操作。

要处理任何任意对象,您可以使用对象克隆功能,例如Armand的答案中列出的功能,或者因为您使用jQuery只需使用$.extend() function。此函数将生成对象的浅拷贝或深拷贝。 (不要将此与用于复制DOM元素的$().clone() method混淆,而不是复制对象。)

浅层副本:

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

或深刻的副本:

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

浅拷贝和深拷贝之间有什么区别?浅拷贝类似于您创建具有对象文字的新对象的代码。它创建一个新的顶级对象,其中包含与原始对象相同属性的引用。

如果您的对象仅包含数字和字符串等基本类型,则深层副本和浅层副本将完全相同。但是如果你的对象包含嵌套在其中的其他对象或数组,那么浅拷贝不会复制那些嵌套对象,它只会创建对它们的引用。因此,您对顶级对象的嵌套对象可能会遇到同样的问题。例如,给定此对象:

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

如果您执行该对象的浅表副本,则新对象的x属性与原始对象的x对象相同:

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

现在您的对象将如下所示:

// 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
    }
};

您可以使用深层复制来避免这种情况。深拷贝会递归到每个嵌套对象和数组(以及Armand代码中的Date),以便像制作顶级对象的副本一样复制这些对象。因此,更改copy.x.y不会影响obj.x.y

简短回答:如果有疑问,您可能需要深层复制。

答案 1 :(得分:48)

我发现使用JSON作品,但请注意我们的循环引用

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

答案 2 :(得分:22)

问题已经解决了很长时间,但是为了将来参考,可能的解决方案是

b = a.slice(0);

注意,只有当a是非嵌套的数字和字符串数组

时,这才能正常工作

答案 3 :(得分:14)

原因很简单。 JavaScript使用引用,因此当您分配b = a时,您正在为b分配引用,因此在更新a时您还要更新b

我在stackoverflow上找到了this,如果你想对对象进行深层复制,只需要调用这个方法就可以防止这样的事情发生。

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.");
}

答案 4 :(得分:7)

newVariable = originalVariable.valueOf();

可以使用的对象,  b = Object.assign({},a);

答案 5 :(得分:6)

我不明白为什么答案如此复杂。在Javascript中,原语(字符串,数字等)按值传递并复制。对象(包括数组)通过引用传递。在任何情况下,为'a'分配新值或对象引用都不会改变'b'。但是改变'a'的内容会改变'b'的内容。

container.Register(
   Classes.FromAssembly(myDynamicAssembly)
      .IncludeNonPublicTypes()
      .BasedOn<ApiController>()
      .LifestylePerWebRequest());

将上述任何行(一次一个)粘贴到节点或任何浏览器javascript控制台中。然后输入任何变量,控制台将显示它的值。

答案 6 :(得分:4)

对于字符串或输入值,您只需使用:

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

答案 7 :(得分:0)

我暂时解决了这个问题。原始值只有2个子属性。我使用a中的属性重新构建了一个新对象,然后将其分配给b。现在,我的事件处理程序仅更新b,原始a保持不变。

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

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

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

这很好用。我没有在我的代码中的任何地方更改过一行,除了上面的内容,它只是我想要的方式。所以,相信我,没有别的东西在更新a

答案 8 :(得分:0)

AngularJS的解决方案:

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

答案 9 :(得分:-1)

这里的大多数答案是使用内置方法或使用库/框架。这个简单的方法应该可以正常工作:

SELECT *
FROM table    
WHERE fieldname % 1 = 0