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

Rut*_*rde 78 javascript jquery

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

var a = $('#some_hidden_var').val(),
    b = a;
Run Code Online (Sandbox Code Playgroud)

这有效,两者都有相同的价值.我使用mousemove事件处理程序来更新b我的应用程序.单击按钮,我想恢复b原始值,即存储的值a.

$('#revert').on('click', function(e){
    b = a;
});
Run Code Online (Sandbox Code Playgroud)

在此之后,如果我使用相同的mousemove事件处理程序,它会同时更新两者,a并且b在更早时它仅b按预期更新.

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

Mic*_*ary 178

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

=运营商不会使拷贝数据.

=操作创建一个新的参考相同的数据.

运行原始代码后:

var a = $('#some_hidden_var').val(),
    b = a;
Run Code Online (Sandbox Code Playgroud)

ab现在为两个不同的名称相同的对象.

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

因此,当您稍后尝试使用此代码"恢复" b到原始a对象时:

b = a;
Run Code Online (Sandbox Code Playgroud)

代码实际上什么都不做,因为a并且b完全相同.代码与您编写的代码相同:

b = b;
Run Code Online (Sandbox Code Playgroud)

这显然不会做任何事情.

为什么新代码有效?

b = { key1: a.key1, key2: a.key2 };
Run Code Online (Sandbox Code Playgroud)

在这里,您将使用{...}对象文字创建一个全新的对象.这个新对象与旧对象不同.所以你现在设置b为这个新对象的引用,它可以满足您的需求.

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

对于浅拷贝:

b = $.extend( {}, a );
Run Code Online (Sandbox Code Playgroud)

或深刻的副本:

b = $.extend( true, {}, a );
Run Code Online (Sandbox Code Playgroud)

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

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

var obj = {
    w: 123,
    x: {
        y: 456,
        z: 789
    }
};
Run Code Online (Sandbox Code Playgroud)

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

var copy = $.extend( {}, obj );
copy.w = 321;
copy.x.y = 654;
Run Code Online (Sandbox Code Playgroud)

现在你的对象看起来像这样:

// 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
    }
};
Run Code Online (Sandbox Code Playgroud)

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

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

  • @MichaelGeary它可能是挑剔但是规则不适用于对象而不是原始变量?在答案中可能值得注意 (6认同)

ker*_*ode 49

我发现使用JSON作品,但看我们的循环引用

var newInstance = JSON.parse(JSON.stringify(firstInstance));
Run Code Online (Sandbox Code Playgroud)

  • 我意识到这有点晚了,但是这个方法有问题吗?它似乎在第一次尝试时令人惊讶地工作. (2认同)
  • 这几乎在所有情况下都很棒,但是如果您正在处理可能呈圆形的数据,它会使您的程序崩溃。一些代码来说明:`let a = {}; 让 b = {a:a}; ab = b; JSON.stringify(a)` 会给出一个 TypeError (2认同)

mar*_*osh 23

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

b = a.slice(0);
Run Code Online (Sandbox Code Playgroud)

请注意,只有当a是非嵌套的数字和字符串数组时,这才能正常工作


Arm*_*and 14

这样做的原因是简单的.JavaScript使用b = a引用,因此当您分配时,您正在分配引用,b因此在更新时a您也在更新b

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

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.");
}
Run Code Online (Sandbox Code Playgroud)


Kis*_*til 11

newVariable = originalVariable.valueOf();

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

  • 对于可以使用的对象,b = Object.assign({},a); (3认同)

Tre*_*ams 6

我不明白为什么答案如此复杂.在Javascript中,原语(字符串,数字等)按值传递并复制.对象(包括数组)通过引用传递.在任何情况下,为'a'分配新值或对象引用都不会改变'b'.但改变'a'的内容将改变'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'
Run Code Online (Sandbox Code Playgroud)

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