1.介绍
深拷贝:拷贝前后没关系,改变拷贝后的值不会影响拷贝前的值
浅拷贝:拷贝前后有关系,拷贝的是引用,所以修改引用对象会影响。
对于数据类型,地址指针,存储方式还有不明白的建议看我这两篇文章
每日一面——仿写reverse方法
JS核心知识点梳理——变量篇
2.浅拷贝
2.1浅拷贝举例
我们先看一下扩展运算符...
let o = {name: 'fyy'}
let obj = {...o}
console.log(obj)//{name: 'fyy'}
obj.name = 1
console.log(o)//{name: 'fyy'}
如果对象只有一层,没有问题,但是一旦对象有两层
let o = {name: {firstname: 'f'}}
let obj = {...o}
console.log(obj)//{name: {firstname: 'f'}}
obj.name.firstname = 1
console.log(o)//{name: {firstname: 1}}
拷贝后的对象就会影响拷贝前的对象了
所以说展运算符...是浅拷贝
同理,object.assign concat slice 都是浅拷贝
浅拷贝的危害
写代码的时候,复制一个变量很常见,如果使用了浅拷贝,那么变量深层属性的访问就变成了多入口了。换句话说,可能我改变量A的某个属性,可能B变量的某个属性也变了。这将导致问题难以追踪,违反了单一性原则,所以我们应该避免浅拷贝。
浅拷贝原因
为什么会出现浅拷贝这种现象呢,因为上面的拷贝,如果属性值不是基础类型,拷贝的是地址,拷贝前后引用的同一个地址,所以能相互影响
比如{name:'fyy'} 如果name的属性值是基本类型,拷贝后的新创建一个该基础类型new String('fyy'),并指向它
但是如果是{name:{firstname:'f'}} 如果name的属性值是对象,则直接把原对象中name指向的地址给新对象中的name。
浅拷贝拷贝的是引用,指向的还是同一个对象。
3.深拷贝
我们保证每次递归拷贝都是新对象就能实现深拷贝。
JSON.parse(JSON.stringify())
第一种实现深拷贝的方法,但是如果对象里面有函数,这种方法不行
这种方法对于处理后台返回来的数据还是挺快的,瑕不掩瑜
递归实现
每次都生成一个新对象
function deppClone(obj) {
if(obj == null ) return undefined
// 如果是Date,RegExp实例,则从新返回一个这种实例
if(obj instanceof Date) return new Date(obj)
if(obj instanceof RegExp) return new RegExp(obj)
//如果是基础类型,则返回基础类型,如果是方法则返回方法(因为方法里面不会有层级)
if(typeof obj !== 'object') return obj
//剩下的可嫩是数组或者是对象,返回相应的对象后者数组
let newobj = new obj.constructor
for(let key in obj) {
if(obj.hasOwnProperty(key)){ //是自己的属性
newobj[key] =deppClone(obj[key]) //但是可以是一个对象,所以还要递归一下
}
}
return newobj
}
面试能写到这,基本高分通过了。
不过还有一个小问题
如果存在循环引用怎么办
obj.p = obj
循环引用
在遍历的时候p这个属性是对象obj,会触发deppClone方法,在遍历的时候p这个属性是对象obj,会触发deppClone方法.....无限循环了,所以已经deepclone了obj,再递归的时候我就不能再deepclone了obj 我需要将所有的深克隆的对象收集起来,拷贝之前进行对比,没有则拷贝,有的话就不用拷贝了,用之前已经拷贝过的
function deepClone(obj,hash=new WeakMap()) {
if(obj == null ) return undefined
// 如果是Date,RegExp实例,则从新返回一个这种实例
if(obj instanceof Date) return new Date(obj)
if(obj instanceof RegExp) return new RegExp(obj)
//如果是基础类型,则返回基础类型,如果是方法则返回方法(因为方法里面不会有层级)
if(typeof obj !== 'object') return obj
if(hash.get(obj)) return hash.get(obj)
//剩下的可嫩是数组或者是对象,返回相应的对象后者数组
let newobj = new obj.constructor
hash.set(obj,newobj)
for(let key in obj) {
if(obj.hasOwnProperty(key)){ //是自己的属性
newobj[key] =deepClone(obj[key],hash) //但是可以是一个对象,所以还要递归一下
}
}
return newobj
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。