我有一个变量,它有一个JSON对象作为其值。我直接将此变量分配给其他变量,以便它们共享相同的值。这是它的工作原理:
var a = $('#some_hidden_var').val(),
b = a;
这有效,两者都有相同的价值。我使用mousemove
事件处理程序通过我的应用程序更新b
。点击按钮,我想将b
恢复为原始值,即a
中存储的值。
$('#revert').on('click', function(e){
b = a;
});
在此之后如果我使用相同的mousemove
事件处理程序,它会同时更新a
和b
,之前它只按预期更新b
。
我很难过这个问题!这有什么不对?
答案 0 :(得分:171)
了解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()
function。此函数将生成对象的浅拷贝或深拷贝。 (不要将此与用于复制DOM元素的$().clone()
method混淆,而不是复制对象。)
浅层副本:
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
。
简短回答:如果有疑问,您可能需要深层复制。
答案 1 :(得分:48)
我发现使用JSON作品,但请注意我们的循环引用
var newInstance = JSON.parse(JSON.stringify(firstInstance));
答案 2 :(得分:22)
问题已经解决了很长时间,但是为了将来参考,可能的解决方案是
b = a.slice(0);
注意,只有当a是非嵌套的数字和字符串数组
时,这才能正常工作答案 3 :(得分:14)
原因很简单。 JavaScript使用引用,因此当您分配b = a
时,您正在为b
分配引用,因此在更新a
时您还要更新b
我在stackoverflow上找到了this,如果你想对对象进行深层复制,只需要调用这个方法就可以防止这样的事情发生。
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.");
}
答案 4 :(得分:7)
newVariable = originalVariable.valueOf();
可以使用的对象, b = Object.assign({},a);
答案 5 :(得分:6)
我不明白为什么答案如此复杂。在Javascript中,原语(字符串,数字等)按值传递并复制。对象(包括数组)通过引用传递。在任何情况下,为'a'分配新值或对象引用都不会改变'b'。但是改变'a'的内容会改变'b'的内容。
container.Register(
Classes.FromAssembly(myDynamicAssembly)
.IncludeNonPublicTypes()
.BasedOn<ApiController>()
.LifestylePerWebRequest());
将上述任何行(一次一个)粘贴到节点或任何浏览器javascript控制台中。然后输入任何变量,控制台将显示它的值。
答案 6 :(得分:4)
对于字符串或输入值,您只需使用:
var a = $('#some_hidden_var').val(),
b = a.substr(0);
答案 7 :(得分:0)
我暂时解决了这个问题。原始值只有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 };
});
这很好用。我没有在我的代码中的任何地方更改过一行,除了上面的内容,它只是我想要的方式。所以,相信我,没有别的东西在更新a
。
答案 8 :(得分:0)
AngularJS的解决方案:
$scope.targetObject = angular.copy($scope.sourceObject)
答案 9 :(得分:-1)
这里的大多数答案是使用内置方法或使用库/框架。这个简单的方法应该可以正常工作:
SELECT *
FROM table
WHERE fieldname % 1 = 0