修改JavaScript对象的副本会导致原始对象发生更改

时间:2015-03-14 14:25:13

标签: javascript object copy

我正在将myObj复制到tempMyObj

var tempMyObj = myObj;

tempMyObj.entity是一个对象数组。我正在根据某些条件修改tempMyObj.entity。问题是如果我修改tempMyObj.entitymyObj.entity也会被修改。

for (j = 0; j < myObj.length; j++) {
    if (myObj[j].type == "TableShape") {
        var dupEntites = new Array();
        for (i = 0; i < myObj[j].entities.length; i++) {
            if (chk.value != myObj[j].entities[i].id) {
                var obj = {};
                obj.text = myObj[j].entities[i].text;
                obj.id = myObj[j].entities[i].id;
                dupEntites.push(obj);
            }
            else {
                if (chk.checked)
                {
                    var obj = {};
                    obj.text = myObj[j].entities[i].text;
                    obj.id = myObj[j].entities[i].id;
                    dupEntites.push(obj);
                }
            }
        }
        tempMyObj[j].entities = dupEntites;
    }
}

9 个答案:

答案 0 :(得分:55)

很明显,您对var tempMyObj = myObj;语句的含义存在一些误解。

在JavaScript中,对象通过引用传递和分配(更准确地说是引用的值),因此tempMyObjmyObj都是对同一对象的引用。

这是一个简化的插图,可以帮助您想象正在发生的事情

// [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);

使用vanilla 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);

请参阅herehere

答案 1 :(得分:3)

尝试使用如下所述的create()方法。

var tempMyObj = Object.create(myObj);

这将解决问题。

答案 2 :(得分:2)

尝试使用$.extend()

  

但是,如果要保留两个原始对象,则为   可以通过传递一个空对象作为目标来实现:

     

var object = $.extend({}, object1, object2);


var tempMyObj = $.extend({}, myObj);

答案 3 :(得分:2)

具有JSON.parse()和JSON.stringify的深层克隆对象

// Deep Clone
obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));

引用:this article

答案 4 :(得分:1)

这可能非常棘手,让我尝试以简单的方式进行说明。当您将一个变量“复制”到javascript中的另一个变量时,实际上并没有将其值从一个变量复制到另一个变量,而是分配给复制的变量,即对原始对象的引用。要实际制作副本,您需要使用来创建新对象

棘手的部分是因为为复制的变量分配新值和修改其值之间存在差异。当您为复制变量分配新值时,您将摆脱引用并为副本分配新值,但是,如果您仅修改副本的值(不分配新值),那么您将修改副本和原始副本

希望该示例有所帮助!

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!

答案 5 :(得分:1)

如果您对数组有同样的问题,那么这里是解决方案

let sectionlist = [{"name":"xyz"},{"name":"abc"}];
let mainsectionlist = [];
for (let i = 0; i < sectionlist.length; i++) {
     mainsectionlist[i] = Object.assign({}, sectionlist[i]);
}

答案 6 :(得分:1)

总而言之,为了澄清起见,复制 JS 对象有三种方式。

  1. 一个普通副本。当您更改原始对象的属性时,复制对象的属性也会更改(反之亦然)。
const a = { x: 0}
const b = a;
b.x = 1; // also updates a.x
  1. 浅拷贝。对于原始对象和复制对象,顶级属性将是唯一的。嵌套属性将在两个对象之间共享。使用扩展运算符 ...{}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
  1. 深拷贝。原始对象和副本对象的所有属性都是唯一的,甚至嵌套的属性也是如此。对于深层复制,请将对象序列化为 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
  1. 使用 Object.create() 确实会创建一个新对象。属性在对象之间共享(改变一个也会改变另一个)。与普通副本的不同之处在于,在新对象的原型 __proto__ 下添加了属性。当您从不更改原始对象时,这也可以用作浅拷贝,但我建议您使用上述方法之一,除非您特别需要这种行为。

答案 7 :(得分:0)

在新变量中使用三个点来展开对象

const a = {b: 1, c: 0};
let d = {...a};

答案 8 :(得分:-1)

将原始对象序列化为 JSON 并反序列化为另一个相同类型的对象变量。这将为您提供具有所有属性值的对象副本。并且对原始对象的任何修改都不会影响复制的对象。

string s = Serialize(object); //Serialize to JSON
//Deserialize to original object type
tempSearchRequest = JsonConvert.DeserializeObject<OriginalObjectType>(s);