JavaScript之浅深拷贝

7次阅读

共计 1817 个字符,预计需要花费 5 分钟才能阅读完成。

前言

JavaScript 里面浅拷贝和深拷贝是非常关键的知识点,今天就来通过本文清楚的了解深浅拷贝以及该如何实现这两种拷贝方式。


深浅拷贝的区别

  • 拷贝:其实就是一个对象复制给另外一整个对象,让对象相互不影响。对象的拷贝又分为浅拷贝和深拷贝。
  • 对象的浅拷贝(只拷贝一层),所谓的浅拷贝,只是拷贝了基本类型的数据,对于引用的类型数据,复制后也是会发生引用,这种拷贝就叫做浅拷贝。
  • 对象的深拷贝(拷贝多层),要求要复制一个复杂的对象,这就可以利用递归的思想来实现,省性能又不会发生引用,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。
  • 浅拷贝和深拷贝只针对 object 这样的复杂的对象而深拷贝,因为对于所有的基本类型,简单的赋值已经是实现了深拷贝。

例子 1. 首先来让我们思考一下以下的 a 应该是多少?

显而易见,a 是 1。印证了上述所说的对于所有的基本类型,简单的赋值已经是实现了深拷贝。我们可以简单地理解,这种 b 变了不影响 a 的就叫做深拷贝。

例子 2. 那么在这种情况下,a.name 又是多少呢?
* 以下 44 为假设,下同。

很明显,a.name 是 ’b’。同样我们可以简单地理解,这种 b 变了影响 a 的就叫做浅拷贝。

在例子 2 中,为什么 b 改变了会影响 a 呢?因为我们仅仅是把堆里所记录的地址 44 复制给了 b,所以在后来我们对 b.name 修改时,会对 44 里记录的 name 直接修改,当 a 再去引用的时候已经是被修改过的 44 了。



我们想要在修改时候两者互不影响,应该是要像上图一样,创建一个新地址 55,里面所包含的内容和地址 44 一样,这样在修改时才会互不影响。同样如果引用里还有引用,也要做到内容一样地址不一样,只有两者引用互无关联才能做到互不影响,才能实现了深拷贝。


如何实现深浅拷贝?

在了解了深浅拷贝的区别之后,我们想要实现深浅拷贝的话该怎么办呢?

  • 浅拷贝

1.ES6:object.assign()

var target = {a: 1, b: 1};
var copy1 = {a: 2, b: 2, c: {ca: 21, cb: 22, cc: 23}};
var copy2 = {c: {ca: 31, cb: 32, cd: 34}};
var result = Object.assign(target, copy1, copy2);
console.log(target);    // {a: 2, b: 2, c: {ca: 31, cb: 32, cc: 33}}
console.log(target === result);    // true

  • 深拷贝

1.JSON.parse() 和 JSON.stringify()

var target = {a: 1, b: 1, c: {ca: 11, cb: 12, cc: 13}};
var targetCopy = JSON.parse(JSON.stringify(target));
targetCopy.a = 2;
targetCopy.c.ca = 21;
console.log(target);   // {a: 1, b: 1, c: {ca: 11, cb: 12, cc: 13}}
console.log(targetCopy);    // {a: 2, b: 1, c: {ca: 21, cb: 12, cc: 13}}
console.log(target === targetCopy);  // false

可以看出通过 JSON.parse() 和 JSON.stringify() 我们可以很简单的实现了深拷贝,但是值得注意的是,JSON.parse() 和 JSON.stringify() 能正确处理的对象只有 Number、String、Array 等能够被 json 表示的数据结构,因此函数、Date 等这种不能被 json 表示的类型将不能被正确处理。

2. 判断类型 + 递归拷贝(不可能复制__proto__)

function clone(object){
    var object2
    if(!(object instanceof Object)){return object}else if(object instanceof Array){object = []
    }else if(object instanceof Function){object = eval(object.toString())
    }else if(object instanceof Object){object = {}
    }
    for(let key in object){object2[key] = clone(object[key])
    }
    return object2
}

正文完
 0