深拷贝、浅拷贝以及直接赋值,到底有啥区别呢?在什么时候我应该用哪一种呢?在一段代码中,我们通常就是拿来直接赋值,直接用。似乎涉及到拷贝的情况没那么多,但是如果对值有操作但是又想保留原先的值,那就不能用直接赋值,需要使用到拷贝。
直接赋值
直接赋值,应该是代码中常见的。但是如果需要对结果进行操作的话,那么不管对象的属性是基本类型还是引用类型都会被修改
let testObj = {
name : 'test',
arr : [1,2,3,4],
test: function (){
console.log('可以复制出来吗?')
}
}
let newObj = testObj
newObj.name = 'newTest'
console.log('testObj',testObj)
console.log('newObj',newObj)
浅拷贝
浅拷贝会比直接赋值好一点,被浅拷贝后,如果是基础类型发生改变,是不会被影响的,但是引用类型还是会被修改。
let testObj = {
name : 'test',
arr : [1,2,3,4],
obj : { nameObj : '测试' } ,
test : function (){
console.log('可以复制出来吗?')
}
}
let newObj = {...testObj}
newObj.name = 'newTest'
newObj.arr[1] = 5
newObj.obj.nameObj = '修改'
console.log('testObj',testObj)
console.log('newObj',newObj)
深拷贝
深拷贝无论是基础类型发生改变,还是引用类型被改变,都不会被修改。下面先用简单的方法实现:
let testObj = {
name : 'test',
age: NaN,
time: new Date(),
arr : [1,2,3,4],
obj : { nameObj : '测试' },
test : function (){
console.log('可以复制出来吗?')
}
}
let newObj = JSON.parse(JSON.stringify(testObj))
newObj.name = 'newTest'
newObj.obj.nameObj = '修改'
console.log('testObj',testObj)
console.log('newObj',newObj)
基础类型和引用类型没有发生改变,但是JSON.stringify对js对象序列化,再通过JSON.parse反序列化还原,会导致函数丢失、时间以字符串的方式展示、对象中的正则表达式也会为空(如图)。所以在使用JSON.stringify和JSON.parse进行深拷贝时要格外注意。下面就对这个简洁版的深拷贝,来个功能完善的基础版。
function deepCopy(obj){
let copy = {}
for(let key in obj) {
if(obj.hasOwnProperty(key)){
copy[key] = obj[key]
}
}
return copy
}
let testObj = {
name : 'test',
age: NaN,
time: new Date(),
arr : [1,2,3,4],
obj : { nameObj : '测试' },
test : function (){
console.log('可以复制出来吗?')
}
}
let newObj = deepCopy(testObj)
newObj.name = 'newTest'
newObj.obj.nameObj = '修改'
console.log('testObj',testObj)
console.log('newObj',newObj)
但上面的写法,也有问题,当对象中有对象时,就还是会被修改,下面用递归来实现。
function deepCopy(obj){
// 在这一步可以加一个判断,判断obj是数组还是object
// let copy = {}
let copy = Array.isArray(obj)? []:{}
// 判断一下obj是否为空,类型
if(obj && typeof obj === 'object') {
for(let key in obj) {
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === 'object'){
// 判断是不是为日期
if(obj[key] instanceof Date){
// 这两种写法都可以
// copy[key] = obj [key]
copy[key] = new Date(obj [key].valueOf())
} else {
copy[key] = deepCopy(obj[key])
}
} else {
copy[key] = obj[key]
}
} else {
copy[key] = obj[key]
}
}
}
}
return copy
}
let testObj = {
name : 'test',
age: NaN,
time: new Date(),
arr : [1,2,3,4],
obj : { nameObj : '测试' },
test : function (){
console.log('可以复制出来吗?')
}
}
let newObj = deepCopy(testObj)
newObj.name = 'newTest'
newObj.arr[1] = 5
newObj.obj.nameObj = '修改'
console.log('testObj',testObj)
console.log('newObj',newObj)