将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
事件处理程序,它会更新a
和b
,如果它早些时候更新只是预期的b
。
我很难过这个问题! 这里有什么问题?
了解JavaScript中的=
运算符是做什么和不做什么是很重要的。
=
运算符不会复制数据。
=
运算符为相同的数据创build一个新的引用 。
运行原始代码后:
var a = $('#some_hidden_var').val(), b = a;
a
和b
现在是同一个对象的两个不同的名字。
无论您是通过variables还是b
variables引用它,您对此对象的内容所做的任何更改都会被视为相同。 他们是同一个对象。
所以,当你以后尝试用这个代码“恢复”到原来的a
对象:
b = a;
代码实际上什么都不做 ,因为a
和b
是完全一样的东西。 代码和你写的一样:
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()