使用 JSON 的 JavaScript 深度复制

问题描述 投票:0回答:4

我对 javascript 对象(数组)深复制有问题。我读了很多处理它的好方法。而且我也知道 jQuery 有 $.extend API 来解决这个问题。但我的问题是:我可以只使用 JSON stringify 和 parse 方法来解决这个问题吗?

这是我的代码:

function deepCopy(oldValue) { 
  var newValue
  strValue = JSON.stringify(oldValue)
  return newValue = JSON.parse(strValue)
}

var a = {
  b: 'b',
  c: [1,2,4],
  d: null
}

copy = deepCopy(a)

console.log(a === copy) // false
console.log(a.c === copy.c) // false

PS:我知道如果不是所有对象都是可序列化的,但我知道的唯一情况是当对象包含一个函数属性时。还有其他情况吗?

javascript json deep-copy
4个回答
44
投票

如果您的对象“小”并且只包含可序列化的属性,则使用 JSON 序列化的简单 deepCopy hack 应该没问题。但是,如果您的对象很大,您可能会遇到问题。如果它包含不可序列化的属性,这些属性将会丢失:

var o = {
 a: 1,
 b: 2,
 sum: function() { return a + b; }
};

var o2 = JSON.parse(JSON.stringify(o));
console.log(o2);

产量:

Object {a: 1, b: 2}

有趣的是,C# 中的相当多的深度复制解决方案都是类似的序列化/反序列化技巧。

附录:不确定您希望在比较复制后的对象方面得到什么。但是,对于复杂的对象,您通常需要编写自己的

Compare()
和/或
Equals()
方法才能进行准确比较。

还值得注意的是,这种副本不保留类型信息。

JSON.parse(JSON.stringify(new A())) instanceof A === false

3
投票

你可以这样做,但由于上面列出的一些原因,这是有问题的:

  1. 我质疑性能。

  2. 你有任何不可序列化的属性吗?

  3. 最大的问题是:您的克隆缺少类型信息。根据您正在做的事情,这可能很重要。实现者是否向原始对象的原型添加了方法?那些都消失了。我不确定你还会失去什么。


0
投票

我认为您正在寻找的是这样的: 如果您有一个真正嵌套的对象结构,那么要进行深层复制,您可以使用 JSON.stringify()。

请看下面的例子:

var obj= {
      'a':1,
      'b':2,
      'c': {
        'd':{
          'e' : 3
        }
      }
    }


var newObj = {...obj};
var lastObj = JSON.parse(JSON.stringify(obj));
obj.c.d.e =19;
console.log('obj '+obj.c.d.e);
console.log('newObj '+obj.c.d.e);
console.log('lastObj'+lastObj.c.d.e); 

现在,lastObj 真正与 obj 分离,而如果您使用 ...(spread) 运算符,它也无法在真正复杂的对象中工作。

希望这有帮助!


0
投票

现在,您可以在现代节点和浏览器环境中使用本机深度克隆:

const value = {
    a: 'a',
    b: 'b',
    foo: {
        "bar": 42
    }
}

const copy = structuredClone(value)

这个类似问题的answer提供了更多选择。

© www.soinside.com 2019 - 2024. All rights reserved.