修改 JavaScript 对象的副本导致原始对象发生变化
Modifying a copy of a JavaScript object is causing the original object to change
我正在复制objA
到objB
const objA = { prop: 1 },
const objB = objA;
objB.prop = 2;
console.log(objA.prop); // logs 2 instead of 1
数组同样的问题
const arrA = [1, 2, 3],
const arrB = arrA;
arrB.push(4);
console.log(arrA.length); // `arrA` has 4 elements instead of 3.
尝试使用 $.extend():
If, however, you want to preserve both of the original objects, you
can do so by passing an empty object as the target:
var object = $.extend({}, object1, object2);
var tempMyObj = $.extend({}, myObj);
很明显,您对语句 var tempMyObj = myObj;
的作用有一些误解。
在JavaScript中,对象是通过引用(更准确地说是引用的值)传递和赋值的,所以tempMyObj
和myObj
都是对同一个对象的引用。
这是一个简化的图示,可以帮助您想象正在发生的事情
// [Object1]<--------- myObj
var tempMyObj = myObj;
// [Object1]<--------- myObj
// ^
// |
// ----------- tempMyObj
正如您在赋值后看到的,两个引用都指向同一个对象。
如果您需要修改一个而不是另一个,您需要创建一个副本。
// [Object1]<--------- myObj
const tempMyObj = Object.assign({}, myObj);
// [Object1]<--------- myObj
// [Object2]<--------- tempMyObj
旧答案:
这里有几种创建对象副本的其他方法
因为您已经在使用 jQuery:
var newObject = jQuery.extend(true, {}, myObj);
有香草味JavaScript
function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
var newObject = clone(myObj);
见here and here
尝试使用如下所述的 create() 方法。
var tempMyObj = Object.create(myObj);
这将解决问题。
这可能很棘手,让我试着用一种简单的方式来表达。当您 "copy" 一个变量到 javascript 中的另一个变量时,您实际上并没有将它的值从一个变量复制到另一个变量,而是将一个 对原始对象的引用分配给复制的变量。要实际制作副本,您需要创建一个新对象 use
棘手的部分是因为为复制的变量分配新值和修改其值之间存在差异。当您分配新值时 到副本变量,您将删除引用并将新值分配给副本,但是,如果您仅 修改副本的值 (不分配新值值),您正在修改副本和原件。
希望示例对您有所帮助!
let original = "Apple";
let copy1 = copy2 = original;
copy1 = "Banana";
copy2 = "John";
console.log("ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); // Apple
console.log(copy1); // Banana
console.log(copy2); // John
//----------------------------
original = { "fruit" : "Apple" };
copy1 = copy2 = original;
copy1 = {"animal" : "Dog"};
copy2 = "John";
console.log("\n ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); //{ fruit: 'Apple' }
console.log(copy1); // { animal: 'Dog' }
console.log(copy2); // John */
//----------------------------
// HERE'S THE TRICK!!!!!!!
original = { "fruit" : "Apple" };
let real_copy = {};
Object.assign(real_copy, original);
copy1 = copy2 = original;
copy1["fruit"] = "Banana"; // we're not assiging a new value to the variable, we're only MODIFYING it, so it changes the copy and the original!!!!
copy2 = "John";
console.log("\n MODIFY the variable without assigning a new value to it, also changes the original variable")
console.log(original); //{ fruit: 'Banana' } <====== Ops!!!!!!
console.log(copy1); // { fruit: 'Banana' }
console.log(copy2); // John
console.log(real_copy); // { fruit: 'Apple' } <======== real copy!
具有 JSON.parse() 和 JSON.stringify
的深度克隆对象
// Deep Clone
obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
参考:this article
更好的参考:this article
如果您对数组有同样的问题,那么这里是解决方案
let sectionlist = [{"name":"xyz"},{"name":"abc"}];
let mainsectionlist = [];
for (let i = 0; i < sectionlist.length; i++) {
mainsectionlist[i] = Object.assign({}, sectionlist[i]);
}
在新变量中使用三个点展开对象
const a = {b: 1, c: 0};
let d = {...a};
将原始对象序列化为JSON并反序列化为另一个相同类型的对象变量。这将为您提供包含所有 属性 值的对象副本。并且对原始对象的任何修改都不会影响复制的对象。
string s = Serialize(object); //Serialize to JSON
//Deserialize to original object type
tempSearchRequest = JsonConvert.DeserializeObject<OriginalObjectType>(s);
总而言之,为了澄清起见,有三种复制 JS 对象的方法。
- 一份普通副本。当您更改原始对象的属性时,复制对象的属性也会更改(反之亦然)。
const a = { x: 0}
const b = a;
b.x = 1; // also updates a.x
- 一个浅拷贝。顶级属性对于原始对象和复制对象将是唯一的。不过,嵌套属性将在两个对象之间共享。使用扩展运算符
...{}
或 Object.assign()
.
const a = { x: 0, y: { z: 0 } };
const b = {...a}; // or const b = Object.assign({}, a);
b.x = 1; // doesn't update a.x
b.y.z = 1; // also updates a.y.z
- 一个深拷贝。所有属性对于原始对象和副本对象都是唯一的,甚至是嵌套属性。对于深层复制,将对象序列化为 JSON 并将其解析回 JS 对象。
const a = { x: 0, y: { z: 0 } };
const b = JSON.parse(JSON.stringify(a));
b.y.z = 1; // doesn't update a.y.z
- 使用
Object.create()
确实创建了一个新对象。属性在对象之间共享(改变一个也会改变另一个)。与普通副本的不同之处在于,在新对象的原型 __proto__
下添加了属性。当您从不 更改原始对象时,这也可以用作浅拷贝,但我建议使用上述方法之一,除非您特别需要这种行为。
由于我找不到此代码 浅copy/cloning 个案例的建议答案,我将把它留在这里:
// shortcuts
const {
create,
getOwnPropertyDescriptors,
getPrototypeOf
} = Object;
// utility
const shallowClone = source => create(
getPrototypeOf(source),
getOwnPropertyDescriptors(source)
);
// ... everyday code ...
const first = {
_counts: 0,
get count() {
return ++this._counts;
}
};
first.count; // 1
const second = shallowClone(first);
// all accessors are preserved
second.count; // 2
second.count; // 3
second.count; // 4
// but `first` is still where it was
first.count; // just 2
与 Object.assign
或 {...spread}
操作相比的主要区别在于,此实用程序将保留进程中的所有访问器、符号等,包括继承。
此 space 中的所有其他解决方案似乎都忽略了这样一个事实,即克隆甚至复制不仅仅是检索一次的属性值,而且访问器和继承在日常情况下可能更受欢迎。
对于其他所有内容,请使用本机 structuredClone
方法或 its polyfill
在 Javascript 中,对象作为引用传递并且它们使用浅层比较,因此当我们更改对象的任何实例时,相同的更改也会引用到主对象。
要忽略此复制,我们可以将 JSON 对象字符串化。
示例:-
let obj = {
key: "value"
}
function convertObj(obj){
let newObj = JSON.parse(obj);
console.log(newObj)
}
convertObj(JSON.stringify(obj));
我正在复制objA
到objB
const objA = { prop: 1 },
const objB = objA;
objB.prop = 2;
console.log(objA.prop); // logs 2 instead of 1
数组同样的问题
const arrA = [1, 2, 3],
const arrB = arrA;
arrB.push(4);
console.log(arrA.length); // `arrA` has 4 elements instead of 3.
尝试使用 $.extend():
If, however, you want to preserve both of the original objects, you can do so by passing an empty object as the target:
var object = $.extend({}, object1, object2);
var tempMyObj = $.extend({}, myObj);
很明显,您对语句 var tempMyObj = myObj;
的作用有一些误解。
在JavaScript中,对象是通过引用(更准确地说是引用的值)传递和赋值的,所以tempMyObj
和myObj
都是对同一个对象的引用。
这是一个简化的图示,可以帮助您想象正在发生的事情
// [Object1]<--------- myObj
var tempMyObj = myObj;
// [Object1]<--------- myObj
// ^
// |
// ----------- tempMyObj
正如您在赋值后看到的,两个引用都指向同一个对象。
如果您需要修改一个而不是另一个,您需要创建一个副本。
// [Object1]<--------- myObj
const tempMyObj = Object.assign({}, myObj);
// [Object1]<--------- myObj
// [Object2]<--------- tempMyObj
旧答案:
这里有几种创建对象副本的其他方法
因为您已经在使用 jQuery:
var newObject = jQuery.extend(true, {}, myObj);
有香草味JavaScript
function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
var newObject = clone(myObj);
见here and here
尝试使用如下所述的 create() 方法。
var tempMyObj = Object.create(myObj);
这将解决问题。
这可能很棘手,让我试着用一种简单的方式来表达。当您 "copy" 一个变量到 javascript 中的另一个变量时,您实际上并没有将它的值从一个变量复制到另一个变量,而是将一个 对原始对象的引用分配给复制的变量。要实际制作副本,您需要创建一个新对象 use
棘手的部分是因为为复制的变量分配新值和修改其值之间存在差异。当您分配新值时 到副本变量,您将删除引用并将新值分配给副本,但是,如果您仅 修改副本的值 (不分配新值值),您正在修改副本和原件。
希望示例对您有所帮助!
let original = "Apple";
let copy1 = copy2 = original;
copy1 = "Banana";
copy2 = "John";
console.log("ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); // Apple
console.log(copy1); // Banana
console.log(copy2); // John
//----------------------------
original = { "fruit" : "Apple" };
copy1 = copy2 = original;
copy1 = {"animal" : "Dog"};
copy2 = "John";
console.log("\n ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); //{ fruit: 'Apple' }
console.log(copy1); // { animal: 'Dog' }
console.log(copy2); // John */
//----------------------------
// HERE'S THE TRICK!!!!!!!
original = { "fruit" : "Apple" };
let real_copy = {};
Object.assign(real_copy, original);
copy1 = copy2 = original;
copy1["fruit"] = "Banana"; // we're not assiging a new value to the variable, we're only MODIFYING it, so it changes the copy and the original!!!!
copy2 = "John";
console.log("\n MODIFY the variable without assigning a new value to it, also changes the original variable")
console.log(original); //{ fruit: 'Banana' } <====== Ops!!!!!!
console.log(copy1); // { fruit: 'Banana' }
console.log(copy2); // John
console.log(real_copy); // { fruit: 'Apple' } <======== real copy!
具有 JSON.parse() 和 JSON.stringify
的深度克隆对象// Deep Clone
obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
参考:this article
更好的参考:this article
如果您对数组有同样的问题,那么这里是解决方案
let sectionlist = [{"name":"xyz"},{"name":"abc"}];
let mainsectionlist = [];
for (let i = 0; i < sectionlist.length; i++) {
mainsectionlist[i] = Object.assign({}, sectionlist[i]);
}
在新变量中使用三个点展开对象
const a = {b: 1, c: 0};
let d = {...a};
将原始对象序列化为JSON并反序列化为另一个相同类型的对象变量。这将为您提供包含所有 属性 值的对象副本。并且对原始对象的任何修改都不会影响复制的对象。
string s = Serialize(object); //Serialize to JSON
//Deserialize to original object type
tempSearchRequest = JsonConvert.DeserializeObject<OriginalObjectType>(s);
总而言之,为了澄清起见,有三种复制 JS 对象的方法。
- 一份普通副本。当您更改原始对象的属性时,复制对象的属性也会更改(反之亦然)。
const a = { x: 0}
const b = a;
b.x = 1; // also updates a.x
- 一个浅拷贝。顶级属性对于原始对象和复制对象将是唯一的。不过,嵌套属性将在两个对象之间共享。使用扩展运算符
...{}
或Object.assign()
.
const a = { x: 0, y: { z: 0 } };
const b = {...a}; // or const b = Object.assign({}, a);
b.x = 1; // doesn't update a.x
b.y.z = 1; // also updates a.y.z
- 一个深拷贝。所有属性对于原始对象和副本对象都是唯一的,甚至是嵌套属性。对于深层复制,将对象序列化为 JSON 并将其解析回 JS 对象。
const a = { x: 0, y: { z: 0 } };
const b = JSON.parse(JSON.stringify(a));
b.y.z = 1; // doesn't update a.y.z
- 使用
Object.create()
确实创建了一个新对象。属性在对象之间共享(改变一个也会改变另一个)。与普通副本的不同之处在于,在新对象的原型__proto__
下添加了属性。当您从不 更改原始对象时,这也可以用作浅拷贝,但我建议使用上述方法之一,除非您特别需要这种行为。
由于我找不到此代码 浅copy/cloning 个案例的建议答案,我将把它留在这里:
// shortcuts
const {
create,
getOwnPropertyDescriptors,
getPrototypeOf
} = Object;
// utility
const shallowClone = source => create(
getPrototypeOf(source),
getOwnPropertyDescriptors(source)
);
// ... everyday code ...
const first = {
_counts: 0,
get count() {
return ++this._counts;
}
};
first.count; // 1
const second = shallowClone(first);
// all accessors are preserved
second.count; // 2
second.count; // 3
second.count; // 4
// but `first` is still where it was
first.count; // just 2
与 Object.assign
或 {...spread}
操作相比的主要区别在于,此实用程序将保留进程中的所有访问器、符号等,包括继承。
此 space 中的所有其他解决方案似乎都忽略了这样一个事实,即克隆甚至复制不仅仅是检索一次的属性值,而且访问器和继承在日常情况下可能更受欢迎。
对于其他所有内容,请使用本机 structuredClone
方法或 its polyfill
在 Javascript 中,对象作为引用传递并且它们使用浅层比较,因此当我们更改对象的任何实例时,相同的更改也会引用到主对象。
要忽略此复制,我们可以将 JSON 对象字符串化。
示例:-
let obj = {
key: "value"
}
function convertObj(obj){
let newObj = JSON.parse(obj);
console.log(newObj)
}
convertObj(JSON.stringify(obj));