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

IT技术 javascript jquery
2021-01-29 13:06:17

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

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

这有效并且两者具有相同的value。我使用mousemove事件处理程序来更新b我的应用程序。单击按钮时,我想恢复b到原始值,即存储在a.

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

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

我被这个问题难住了!这里有什么问题?

6个回答

了解=JavaScript 中运算符做什么和不做什么很重要

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

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

运行原始代码后:

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

a并且b现在是同一个对象的两个不同名称

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

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

b = a;

代码实际上什么都不做,因为ab是完全相同的东西。代码与您编写的代码相同:

b = b;

这显然不会做任何事情。

为什么你的新代码有效?

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

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

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

对于浅拷贝:

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.

简短回答:如果有疑问,您可能需要深拷贝。

谢谢,这正是我要找的。有什么办法可以解决它吗?在我目前的情况下,很容易修复,因为我只有 2 个属性。但可能有更大的物体。
2021-03-19 13:06:17
很好的解释迈克尔!
2021-03-19 13:06:17
JS 对此的解决方案在 Armands 的回答中,如 Michael Geary 所说。=
2021-03-23 13:06:17
@MichaelGeary 这可能是吹毛求疵,但规则是否仅适用于对象而不适用于原始变量?在答案中可能值得注意
2021-03-24 13:06:17
Armand 的答案有一个对象克隆函数可以解决这个问题。或者,由于您使用的是 jQuery,您可以使用内置$.extend()函数。详情如上。:-)
2021-04-02 13:06:17

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

var newInstance = JSON.parse(JSON.stringify(firstInstance));
我意识到这有点晚了,但是这种方法有问题吗?它似乎在第一次尝试时效果惊人。
2021-03-27 13:06:17
这几乎在所有情况下都很好,但是如果您正在处理可能呈圆形的数据,它会使您的程序崩溃。一些代码来说明: let a = {}; let b = {a:a}; a.b = b; JSON.stringify(a)会给出一个 TypeError
2021-03-30 13:06:17
这个解决方案效果很好。然而,这在加工过程中有多昂贵?这似乎是通过双重否定起作用的。
2021-04-13 13:06:17

newVariable = originalVariable.valueOf();

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

对于您可以使用的对象,b = Object.assign({},a);
2021-03-23 13:06:17

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

b = a.slice(0);

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

这样做的原因是简单的。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.");
}
谢谢!我在发布新问题之前看到了那个帖子。但我不确定这对我的场景是否有帮助。原来这就是我需要的。
2021-03-19 13:06:17
@Zac 在这种情况下不是。每个 if-body(感兴趣的)都返回一个值。(在下一个 if 之前退出函数)
2021-03-25 13:06:17
除了第一个之外,不应该if (obj instanceof x) { ... }是 else if 吗?
2021-04-07 13:06:17