复制对象

94 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天,点击查看活动详情

复制对象

如何复制一个对象?

这个问题既简单又复杂。我们都知道深拷贝浅拷贝,一般是针对引用对象来说,因为对于基本类型数据,也不存在深拷贝。引用对象属性值中存的都是对象的存储地址,非对象本身,如果是浅拷贝,仅拷贝对象的存储地址,深拷贝的话会把对象本身也要进行拷贝,可能就会出现很多问题。

思考如下代码:

function anotherFunction () {}
var anotherObject = {
  c: true
}
var anotherArray = []
var myObject = {
  a: 2,
  b: anotherObject,
  c: anotherArray,
  d: anotherFunction
}
anotherArray.push(anotherObject, myObject)

现在假如我们需要复制myObject对象,如何做呢?

myObject对象的b、c、d属性都是引用变量,变量存储的都是地址值,这倒不是最麻烦的。最麻烦的是myObject的变量c存储了anotherArray的值,而anotherArray数组中又有myObjectanotherObject,这样就陷入了死循环似的相互引用了。

在复制的时候,我们检测到了这种死循环是应该终止循环不复制更深层元素呢?或者选择直接就报错了,都可以是不同的选择方案。

对于JSON安全,也就是可以被序列化为一个JSON字符串并且可以根据这个字符串解析出一个结构和值完全一样的对象来说,可以使用我们比较常见的赋值方法:

var newObj = JSON.parse(JSON.stringify(obj))

这里需要保证JSON是安全的,仅适用于部分情况。这里JSON.stringify当obj是循环引用时,则会抛出异常TypeError: cyclic object value(循环对象值)

还有当尝试去转换BigInt类型的时候,也会抛出错误TypeError,因为BigInt值不能被JSON序列化。

相比深拷贝,浅拷贝要容易的多,因为它不必关系引用背后的对象。在ES6中可以使用Object.assign()方法来实现浅拷贝。第一个参数是目标对象,后面可以是一个或多个源对象。

var obj1 = {
  a: 1
}
var obj2 = {
  b: 2
}
var newObj = Object.assign({}, obj1, obj2)
console.log(newObj) // var obj1 = {
  a: 1
}
var obj2 = {
  b: 2
}
var newObj = Object.assign({}, obj1, obj2)
console.log(newObj) // {a:1, b:2}