将variables的值复制到另一个

我有一个具有JSON对象作为其值的variables。 我直接把这个variables分配给其他一些variables,以便它们共享相同的值。 这是如何工作的:

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

这工作,并具有相同的价值。 我使用mousemove事件处理程序更新b通过我的应用程序。 在一个button上单击,我想将b恢复为原始值,即存储在a的值。

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

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

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

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

=运算符不会复制数据。

=运算符为相同的数据创build一个新的引用

运行原始代码后:

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

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

无论您是通过variables还是bvariables引用它,您对此对象的内容所做的任何更改都会被视为相同。 他们是同一个对象。

所以,当你以后尝试用这个代码“恢复”到原来的a对象:

 b = a; 

代码实际上什么都不做 ,因为ab是完全一样的东西。 代码和你写的一样:

 b = b; 

这显然不会做任何事情。

为什么你的新代码工作?

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

在这里,您正在使用{...}对象字面值创build一个全新的对象。 这个新对象与你的旧对象不一样。 所以你现在将b设置为这个新对象的引用,这个对象就是你想要的。

为了处理任意的对象,你可以使用Armand的答案中列出的对象克隆函数,或者因为使用jQuery,只需使用$.extend()函数 。 这个函数将使对象的浅拷贝或深拷贝。 (不要将它与用于复制DOM元素的$().clone()方法混淆,而不是对象)。

对于浅拷贝:

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

或者是一个深层复制:

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

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

如果你的对象只包含像数字和string这样的基本types,那么深度复制和浅层复制将完全相同。 但是,如果你的对象包含嵌套在其中的其他对象或数组,那么浅拷贝不会复制这些嵌套对象,它只是创build对它们的引用。 所以你可能会遇到和顶层对象一样的嵌套对象的问题。 例如,给定这个对象:

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

如果你做了一个该对象的浅拷贝,那么你的新对象的x属性就是原来的x对象:

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

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

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

您可以通过深层复制来避免这种情况。 深层副本recursion到每个嵌套的对象和数组(以及Armand的代码中的Date)中,以与创build顶层对象副本相同的方式复制这些对象。 所以改变copy.xy不会影响obj.xy

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

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

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

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

 b = a.slice(0); 

要小心,只有当a是一个非嵌套的数字和string数组时,才能正确工作

这样做的原因是简单的。 JavaScript使用引用,所以当你分配b = a你正在给b分配一个引用,因此在更新时你也在更新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."); } 

对于string或input值,你可以简单地使用这个:

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

我不明白为什么答案如此复杂。 在Javascript中,基元(string,数字等)通过值传递,并被复制。 对象(包括数组)通过引用传递。 在任何情况下,赋值“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; aa = 'c'; // ba === 'c' and aa === 'c' 

粘贴上面的任何一行(一次一个)到节点或任何浏览器的JavaScript控制台。 然后input任何variables,控制台将显示它的值。

我暂时自己解决了。 原始值只有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 }; }); 

这工作正常。 除了上面的代码外,我还没有在代码中的任何地方更改过任何一行代码,它的工作原理就是我想要的。 所以,相信我,没有其他更新。

newVariable = originalVariable.valueOf()