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

我有一个变量,它的值是一个 JSON 对象。我直接将这个变量赋给其他变量,以便它们共享相同的值。事情是这样的:

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

这种方法是有效的,并且两者具有相同的价值。我使用 mousemove事件处理程序通过我的应用程序更新 b。在单击按钮时,我想将 b还原为原始值,即存储在 a中的值。

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

之后,如果我使用相同的 mousemove事件处理程序,它会同时更新 ab,而之前它只是按照预期更新 b

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

274590 次浏览

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

原因很简单。JavaScript 使用引用,因此当您分配 b = a时,您是在分配对 b的引用,因此当更新 a时,您也是在更新 b

I found 这个 on stackoverflow and will help prevent things like this in the future by just calling this method if you want to do a deep copy of an object.

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.");
}

了解 JavaScript 中的 =操作符的作用和不作用非常重要。

=操作符不对数据进行 收到操作。

=操作符为 一样数据创建一个新的 参考文献

在运行原始代码之后:

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

ab现在是 同样的东西的两个不同名称。

无论您通过 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 );

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

If your object contains only primitive types like numbers and strings, a deep copy and shallow copy will do exactly the same thing. But if your object contains other objects or arrays nested inside it, then a shallow copy doesn't 收到 those nested objects, it merely creates references to them. So you could have the same problem with nested objects that you had with your top-level object. For example, given this object:

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

Short answer: If in doubt, you probably want a deep copy.

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

b = a.slice(0);

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

我发现使用 JSON 是可行的,但请注意我们的循环引用

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

对于字符串或输入值,您可以简单地使用:

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

我不明白为什么答案这么复杂。在 Javascript 中,原语(字符串、数字等)通过值传递和复制。对象(包括数组)通过引用传递。在任何情况下,将新值或对象引用赋给“ 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; a.a = 'c'; // b.a === 'c' and a.a === 'c'

粘贴以上任何一行(一次一行)到节点或任何浏览器的 javascript 控制台。然后键入任何变量,控制台将显示它的值。

newVariable = originalVariable.valueOf();

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

A solution for AngularJS:

$scope.targetObject = angular.copy($scope.sourceObject)

这里的大多数答案都是使用内置的方法或者使用库/框架,这个简单的方法应该可以很好地工作:

function copy(x) {
return JSON.parse( JSON.stringify(x) );
}


// Usage
var a = 'some';
var b = copy(a);
a += 'thing';


console.log(b); // "some"


var c = { x: 1 };
var d = copy(c);
c.x = 2;


console.log(d); // { x: 1 }