概念
浅拷贝和深拷贝都可在已有对象的基础上再生一份,但对象的实例存储在堆内存中然后通过一个引用值去操作对象,由此拷贝的时候就存在两种情况了:拷贝引用和拷贝实例,这也是浅拷贝和深拷贝的区别所在。
- 浅拷贝:浅拷贝是拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响。
- 深拷贝:深拷贝不是简单的拷贝引用,而是在堆中重新分配内存,并且把源对象实例的所有属性都进行新建拷贝,以保证深拷贝的对象的引用不包含任何原有对象或对象上的任何对象,拷贝后的对象与原来的对象是完全隔离的。
浅拷贝
浅拷贝就是简单的引用拷贝
var src = {
name:"src";
}
var target = src; //复制一份src对象的引用
target.name = "target"; //改变复制后对象的name值
console.log(src.name); //输出target,即原对象也发生了改变,证明复制的是指向堆内存内对象位置的引用
- 使用Object.assign
let objA = {
name: 'a'
}
let objB = Object.assign({}, objA)
console.log(objB)
objB.name = 'b'
console.log(objA.name)
{name: "a"}
a
深拷贝
- 递归实现
function deepCopy(oldObj, newObj) {
var newObj = newObj || {}
for (var i in oldObj) {
if (oldObj[i] instanceof Object) {
if (oldObj[i].constructor === Array) {
newObj[i] = []
} else {
newObj[i] = {}
}
deepCopy(oldObj[i], newObj[i])
} else {
newObj[i] = oldObj[i]
}
}
return newObj
}
var obj1 = {
country: 'China',
city: ['Beijing,Shanghai,Nanjing'],
age: 16,
friends: {
name: 'dot',
sex: 'female',
age: null
}
}
var obj2 = {
name: 'dolby',
fav: 'food'
}
var obj3 = null
console.log(deepCopy(obj1, obj2))
//{ name: 'dolby',
// fav: 'food',
// country: 'China',
// city: [ 'Beijing,Shanghai,Nanjing' ],
// age: 16,
// friends: { name: 'dot', sex: 'female', age: null } }
console.log(deepCopy(obj1, obj3))
//{ country: 'China',
// city: [ 'Beijing,Shanghai,Nanjing' ],
// age: 16,
// friends: { name: 'dot', sex: 'female', age: null } }
- JSON对象的parse()和stringify()方法
stringify()方法将JS对象序列化成JSON字符串,parse()方法将JSON字符串反序列化成JS对象,借助这两个方法可以实现对象的深拷贝。
var obj1 = {
country: 'China',
city: ['Beijing', 'Shanghai', 'Nanjing'],
age: 16,
friends: {
name: 'dot',
sex: 'female',
age: null
}
}
var deepCopyObj = JSON.parse(JSON.stringify(obj1))
console.log(deepCopyObj)
//{ country: 'China',
// city: [ 'Beijing', 'Shanghai', 'Nanjing' ],
// age: 16,
// friends: { name: 'dot', sex: 'female', age: null } }
deepCopyObj.age = 0
deepCopyObj.city[1] = 'tianjin'
console.log(deepCopyObj)
//{ country: 'China',
// city: [ 'Beijing', 'tianjin', 'Nanjing' ],
// age: 0,
// friends: { name: 'dot', sex: 'female', age: null }
console.log(obj1)
//{ country: 'China',
// city: [ 'Beijing', 'Shanghai', 'Nanjing' ],
// age: 16,
// friends: { name: 'dot', sex: 'female', age: null } }
从代码输出看出,拷贝后的deepCopyObj与obj1完全隔离,二者不会相互影响。
这个方法可满足基本的深拷贝需求,而且能够处理JSON格式能表示的所有数据类型(即 Number, String, Boolean, Array),但对于正则表达式类型、函数类型等无法进行深拷贝(而且会直接丢失相应的值),同时如果对象中存在循环引用的情况也无法正确处理。
注意:如果对象比较大,层级比较多,深拷贝会带来性能上的问题,在遇到需要采用深拷贝的场景时可以考虑看看有没有其他替代的方案,在实际应用场景中也是浅拷贝更为常用。
网友评论