重要的是要了解JavaScript中的运算符做什么和不做什么。=
=
运算符不创建数据的副本。
=
运算符创建对相同数据的新引用。
运行原始代码后:
var a = $('#some_hidden_var').val(),
b = a;
a
并且现在是同一对象的两个不同名称。b
无论通过变量还是变量引用此对象,对此对象的内容所做的任何更改都将以相同的方式显示。它们是同一个对象。a
b
因此,当您稍后尝试使用此代码“还原”到原始对象时:b
a
b = a;
代码实际上根本不做任何事情,因为和是完全一回事。代码与您编写的代码相同:a
b
b = b;
这显然不会做任何事情。
为什么你的新代码可以工作?
b = { key1: a.key1, key2: a.key2 };
在这里,您将创建一个具有对象文本的全新对象。此新对象与旧对象不同。因此,您现在正在设置为对此新对象的引用,该对象执行所需的操作。{...}
b
要处理任何任意对象,您可以使用对象克隆函数,例如Armand的答案中列出的函数,或者由于您正在使用jQuery,因此只需使用$.extend()
函数。此函数将创建对象的浅副本或深层副本。(不要将其与 $().clone()
方法混淆,后者用于复制 DOM 元素,而不是对象。
对于浅副本:
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
简短的回答:如果有疑问,你可能想要一个深度副本。