-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
浅拷贝与深拷贝 #5
Labels
JavaScript
javaScript
Comments
Open
第三节中的shallowCopy的实现似乎不是第四节中的浅拷贝的实现方式,反而像第五节中深拷贝的第二种实现方法 |
并不一样。shallowCopy没有判断对象属性值的类型,所以属性值必须是基础类型,属于浅拷贝 |
for in 遍历对象时,会访问挂载在原型链上的属性,所以需要加一个判断,hasOwnProperty() |
深拷贝,手写递归方法,需要添加对函数的拷贝吧? |
@zelingo 你贴一下代码 |
循环引用呢? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
前言
在 javascript 中有不同的方法来复制对象,如果你还不熟悉这门语言的话,复制对象时就会很容易掉进陷阱里,那么我们怎样才能正确地复制一个对象呢?
读完本文,希望你能明白:
浅拷贝与深拷贝
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
借助ConardLi大佬以下两张图片,帮我们更好的理解两者的含义:
总而言之,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
赋值和深/浅拷贝的区别
这三者的区别如下,不过比较的前提都是针对引用类型:
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
我们先来看下面的例子,对比赋值与深/浅拷贝得到的对象修改后对原始对象的影响:
上面例子中,obj1是原始对象,obj2是赋值操作得到的对象,obj3浅拷贝得到的对象,obj4深拷贝得到的对象,通过下面的表格,我们可以很清晰看到他们对原始数据的影响:
浅拷贝的实现方式
1.Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
2.函数库lodash的_.clone方法
该函数库也有提供_.clone用来做 Shallow Copy,后面我们会再介绍利用这个库实现深拷贝。
3.展开运算符...
展开运算符是一个 es6 / es2015特性,它提供了一种非常方便的方式来执行浅拷贝,这与 Object.assign ()的功能相同。
4.Array.prototype.concat()
5.Array.prototype.slice()
深拷贝的实现方式
1.JSON.parse(JSON.stringify())
这也是利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。
比如下面的例子:
2.函数库lodash的_.cloneDeep方法
该函数库也有提供_.cloneDeep用来做 Deep Copy
3.jQuery.extend()方法
jquery 有提供一個
$.extend
可以用来做 Deep Copy4.手写递归方法
递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
有种特殊情况需注意就是对象存在循环引用的情况,即对象的属性直接的引用了自身的情况,解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝,这样就巧妙化解的循环引用的问题。关于这块如有疑惑,请仔细阅读
ConardLi大佬
如何写出一个惊艳面试官的深拷贝?这篇文章。欢迎关注公众号:前端工匠,你的成长我们一起见证!
参考文章
如何写出一个惊艳面试官的深拷贝?
JavaScript浅拷贝和深拷贝
js 深拷贝 vs 浅拷贝
深拷贝的终极探索(99%的人都不知道)
How to deep clone a JavaScript object
The text was updated successfully, but these errors were encountered: