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

IT技术 javascript object copy
2021-01-18 05:52:34

我复制objAobjB

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.
6个回答

很明显,您对语句的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);

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

这里这里

Object.assign({}, myObj);没有为我创建副本。反而var tempMyObj = Object.create(myObj);奏效了。
2021-03-18 05:52:34
这个答案应该包括如何使用数组也这么做:const arrB = arrA.slice();const arrB = Array.from(arrA);const arrB = [ ...arrA ];
2021-03-18 05:52:34
可能值得注意的是,当您创建自己的对象(例如let a={}; let b=a; b.blah=1;console.log(a)时,这似乎开始抬头我猜很多新手(像我一样)不会注意到这一点,因为很多命令会为我们输出一个新对象(例如 map/filter/etc)。我很难理解为什么有人会理智地想要当前的行为......
2021-03-29 05:52:34
没问题!当我对已回答的问题进行如此广泛的编辑时,我会尝试跟进。:)
2021-04-02 05:52:34
@JAAulde,感谢您更新答案,发布您对问题的更新。我不确定我是否会抓住它。
2021-04-09 05:52:34

使用 JSON.parse() 和 JSON.stringify 深度克隆对象

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

参考:这篇文章

更好的参考这篇文章

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

var tempMyObj = Object.create(myObj);

这将解决问题。

虽然你的答案是正确的,而且绝对适合这里。但是使用 Object.create() 有一个缺点。它将属性添加到对象的proto _ proto_而不是对象。Object.assign() 将属性添加到对象。
2021-03-12 05:52:34

尝试使用$.extend()

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

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


var tempMyObj = $.extend({}, myObj);
JavaScript 现在有一个类似的内置函数,Object.assign(). 用法示例:Object.assign({}, myObj).
2021-03-24 05:52:34
宾果游戏,这就是我要写的……:)
2021-03-27 05:52:34

总而言之,为了澄清起见,有三种复制 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. UsingObject.create()确实会创建一个新对象。属性在对象之间共享(改变一个也会改变另一个)。与普通副本的不同之处在于,在新对象的原型下添加了属性__proto__当您从不更改原始对象时,这也可以用作浅拷贝,但我建议使用上述方法之一,除非您特别需要这种行为。