深拷贝和浅拷贝

深浅拷贝
首先,我们需要明白什么是深拷贝,什么是浅拷贝

深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
假设B复制了A,修改A的时候,看B是否发生变化:

如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)

如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)
//作者:Mike丶 https://www.cnblogs.com/mikeCao/p/8710837.html

深拷贝就意味着,新对象与源对象对比,他们的引用地址发生了变化,举个例子就是出现了两个样貌相同的人,但是他们的家不是同一个地方
而浅拷贝只是复制了源对象的所有,包括引用地址,同样用上面的例子就是2个想通样貌的人,他们的家也是同一个地方。

let a = {
  age: 1
};
let b = a;
a.age = 2;
console.log(b.age) // 2

从上述例子中我们可以发现,如果给一个变量赋值一个对象,那么两者的值会是同
一个引用,其中一方改变,另一方也会相应改变。
通常在开发中我们不希望出现这样的问题,我们可以使用深拷贝来解决这个问题;
首先可以通过 Object.assign 来解决这个问题。

let a = {
 age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1

Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。
也就是说,如果对象的属性值为简单类型(如string, number),通过Object.assign({},sourceObj);得到的新对象为深拷贝;
如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。
...和Object.assign()的行为是一致的。所以同样,如果对象的属性值为简单类型,即只有一层,那么得到的新对象为深拷贝,如果为对象或者其他引用类型,即超过1层,那么得到的新对象为浅拷贝。

let a = {
  age: 1
}let b = {...a}
a.age = 2
console.log(b.age) // 1

那么如何进行多层的深拷贝呢?

let a = {
 age: 1,
 jobs: {
 first: 'FE'
 }
}
let b = {...a}
a.jobs.first = 'native'
console.log(b.jobs.first) // native

浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就又回到刚开始的话题了,两者享有相同的引用。要解决这个问题,我们需要引入深拷贝。

深拷贝

这个问题通常在es5中通过JSON.parse(JSON.stringify(object))来解决。

let a = {
  age: 1,
  jobs: {
  first: 'FE'
  }
}let b = JSON.parse(JSON.stringia.jobs.first = 'native'
le.log(b.jobs.first) // FE

但是该方法也是有局限性的:
• 会忽略 undefined
• 不能序列化函数
• 不能解决循环引用的对象

let a = {
 age: undefined,
 jobs: function() {},
 name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}

你会发现在上述情况中,该方法会忽略掉函数和 undefined 。

但是在通常情况下,复杂数据都是可以序列化的,所以这个函数可以解决大部分问
题,并且该函数是内置函数中处理深拷贝性能最快的。当然如果你的数据中含有以上三
种情况下,可以使用 lodash 的深拷贝函数:cloneDeep
然而lodash的深拷贝对于function和err依然不会成功。
这个时候如果需要继续深拷贝,那么lodash提供了一个自定义深拷贝方法:cloneDeepWith;具体可以在官方文档中研究一下,例如深拷贝dom对象

function customizer(value) {
  if (_.isElement(value)) {
    return value.cloneNode(true);
  }
}
 
var el = _.cloneDeepWith(document.body, customizer);
 
console.log(el === document.body);
// => false
console.log(el.nodeName);
// => 'BODY'
console.log(el.childNodes.length);
// => 20
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 写在前面 各类技术论坛关于深拷贝的博客有很多,有些写的也比我好,那为什么我还要坚持写这篇博客呢,之前看到的一篇博客...
    心_c2a2阅读 21,197评论 3 18
  • 在讲深拷贝和浅拷贝的时候先说一下js的数据类型,因为在我理解而言只有引用类型才有深浅拷贝的概念 基本数据类型 首先...
    神话降临阅读 280评论 0 1
  • 点击进入博客 最近在公司的项目中用到了Java的对象拷贝(Object Copy),准备深入了解一下,试想一下如果...
    _南轩阅读 517评论 0 6
  • 为什么要写这篇博客?在iOS开发中,我们往往将copy和mutableCopy这两个OC的Api的意思来理解深浅拷...
    天线_BOB阅读 2,707评论 1 3
  • 大家好,我是IT修真院成都分院的学员,一枚正直纯洁善良的WEB前端程序员。 今天给大家分享一下,修真院官网JS任务...
    骆驼丶阅读 439评论 0 0