应用场景
我们知道对于拷贝来说,若为引用类型,则拷贝过程为引用拷贝,过程是让新对象所对应的栈中的地址指向旧对象。所以就不可以简单的赋值。也就有了浅拷贝和深拷贝一说。
一、浅拷贝
浅拷贝不考虑待拷贝对象的属性和方法是否为引用类型。
方法一、
var Clone=function(orign)
{
var target= Array.isArray(orign)?[]:{}
for(var key in orign)
{
if(orign.hasOwnProperty(key))//for in会遍历到原型链中的方法
{
target[key]=orign[key]
}
}
return target
}
方法二、
function clone(orign)
{
var target=Array.isArray(orign)?[]:{}
//利用Object.keys+for ...of 剔除原型链
for(var key of Object.keys(orign))
{
target[key]=orign[key]
}
return target
}
方法三、
function clone(orign)
{
var target=Array.isArray(orign)?[]:{}
//利用Object.entires +for ...of 剔除原型链
for(var [key,value] of Object.entries(orign) )
{
target[key]=value
}
return target
}
方法四、
function clone(orign)
{
return Object.assign(orign,{})
}
此外,像array上的slice方法、concat方法都属于浅拷贝。
实现过程主要是要去除原型链上的方法。浅拷贝存在的问题:
var person1={name:'Bob',
age:19,
eat:{b:5}}
var person2=clone(person1)
person2.name='Alice'
person2.eat.b=6
console.log(person1,'----',person2)
根据上面的结果我们可以发现,在对拷贝出来的对象的基本类型进行修改时,待拷贝元素属性不会改变,而在对拷贝出来的对象的引用类型进行修改时,待拷贝元素属性还是发生了变化。那么我们就需要一种方法解决此类问题即深拷贝。
二、深拷贝
方法一:递归+考虑循环引用
深拷贝就是考虑我们的待拷贝对象的属性是否为引用类型,若为引用类型,就要递归处理。
const deepClones = (target, hash = new WeakMap()) => {
if (typeof target !== 'object' || target === null) {
throw ('sss')
}
if (hash.has(target)) {
return hash.get(target)
}
let result;
if (target instanceof Set) {
result = new Set([...target])
} else if (target instanceof Map) {
result = new Map([...target])
} else if (target instanceof Date) {
result = new Date(target)
} else if (target instanceof RegExp) {
result = new RegExp(target)
} else {
result = Array.isArray(target) ? [] : {}
}
hash.set(target, result)
for (let key of Object.keys(target)) {
if (typeof target[key] === 'object' && target[key] !== null) {
result[key] = deepClones(target[key], hash)
} else {
result[key] = target[key]
}
}
return result;
}
方法二:JSON
JSON.stringfy可以将对象转为字符串(原始值),JSON.parse又可以将字符串转为对象,经过这一套操作就可以使拷贝后的对象与拷贝前的对象不指向一个区域。
但是JSON.parse之后不带任何方法,所以不常用:
var JSONfun=function(orign)
{
var str=JSON.stringify(orign)
var target=JSON.parse(str)
return target
}