深拷贝和浅拷贝
前言
深拷贝和浅拷贝的区别,各位大小牛们应该都不陌生,这里主要给前端新人介绍一下,也帮助我自己复习一下。
为什么会突然讲这个呢,最近搬砖有点头晕目眩,趁着有空闲时刻,突然想练习一下递归,看看自己尚能饭否,结果就猪脑过载了。
后来就遇到了深拷贝,毕竟作为一道前端入门的经典面试题,以及和递归相关的题目,出场率也是挺高的。
复制一个对象
在 javascript 里是不能用变量赋值的方式来复制一个对象。因为 javascript 的赋值是值传递,复制对象的引用值到另一个变量,最终会导致 2 个变量都指向同一个对象。
浅拷贝
浅拷贝创建一个新对象,将旧对象的属性依次复制给新对象。
属性值是赋值过去的,如果碰到属性值为对象类型时,则只复制引用值,最终导致新旧对象的同名属性都指向同一个对象。
因此我们通常戏称浅拷贝只复制对象的第一层属性。
我自己写的哦:
1 | function shallow_copy(src) { |
深拷贝
深拷贝创建一个新对象,将旧对象的属性依次复制给新对象。当中遇到对象类型的属性,则创建新的子对象,将旧的子对象的属性复制给新的子对象。
这里区别在于碰到属性值是对象类型时,我们不是简单复制引用值了,而是在内存中创建新对象,然后再进行拷贝。
这种将子孙对象也进行拷贝的做法,就很“深”。
1 | function deep_copy(src) { |
注意事项
在遍历对象的时候我使用了 Object.keys()
,该方法会返回对象自身可枚举属性的集合。
但是有小伙伴可能会使用 for in
来遍历对象的属性,这里就要讲一下区别:
- `Object.keys()` 只会枚举自身属性
- `for in` 不仅会枚举自身属性,还会枚举原型链上的属性
如果自己写一个 Object.keys() 方法,我可能会这样写
1 | Object.keys = function (obj) { |
可以看到我在实现 Object.keys()
时,也使用了 for in
,但是注意,只有自身属性才会被加入集合。
关于 Object.prototype.propertyIsEnumerable
其实只是单纯为了复习一下方法,在这里没有任何作用,因为上 for in
并不能遍历出不可枚举的属性。