Appearance
一、浅拷贝和深拷贝
- 浅拷贝是创建一个新对象,这个新对象和原始对象的属性值一样。如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址,其中一个对象的地址值改变,另一个对象的值也会跟着改变。
- 深拷贝是将对象从内存中完整的拷贝出来,从堆内存中在申请一个新的空间存放新对象。修改新对象不会影响原始对象。
二、对象赋值和深/浅拷贝的区别
- 把一个对象赋值给一个新的变量时,赋值的其实是==对象在栈中的地址,而不是堆中的数据。==也就是两个对象指向的是同一个存储空间,无论哪个对象发生变化,改变的都是堆中存储空间的内容。所以两个对象是相通的。
- 浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,引用类型因为共享同一块内存,会互相影响。
- 深拷贝:从堆内存中开辟一个新的空间,存放新的对象。对对象中的内从进行递归拷贝,拷贝前后的两个对象互相不影响。
三、浅拷贝实现方法
1. 对象浅拷贝
1.1 Object.assign()
Object.assign()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
js
let obj1 = {person:{name:'kole',age:21},sex:'男'}
let obj2 = Object.assign({},obj1)
obj2.person.name = 'xuebi'
obj2.sex = '女'
console.log(obj1)//{person:{name: "xuebi", age: 21}, sex: "男"}1.2 扩展运算符
js
let obj1 = {person:{name:'kole',age:21},sex:'男'}
let obj2 = {...obj1}
obj2.person.age = 52
obj2.sex = '女'
console.log(obj1)//{person: {name: "kole", age: 52}, sex: "男"}
console.log(obj2)//{person: {name: "kole", age: 52}, sex: "女"}2. 数组浅拷贝
Array.prototype.concat()
js
let arr = [1,2,{name:'kole'}]
let arr1 = arr.concat();
arr1[2].name = 'kaka'
arr1[0]=2
console.log(arr)//[1, 2, {name: "kaka"}]
console.log(arr1)//[2, 2, {name: "kaka"}]Array.prototype.slice()
js
let arr = [1,2,{name:'kole'}]
let arr1 = arr.slice();
arr1[2].name = 'kaka'
arr1[0]=2
console.log(arr)//[1, 2, {name: "kaka"}]
console.log(arr1)//[2, 2, {name: "kaka"}]三、深拷贝实现方法
- JSON.parse(JSON.stringify())
js
let arr = [1,2,{name:'kole'}]
let arr1 = JSON.parse(JSON.stringify(arr))
arr1[2].name = 'kaka'
arr1[0] = 2
console.log(arr)//[1, 2, {name: "kole"}]
console.log(arr1)// [2, 2, {name: "kaka"}]这种方法虽然可以实现数组或对象的深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。
js
let arr = [1,2,{name:'kole',age:null,sex:''},function clone (){console.log(123)}]
let arr1 = JSON.parse(JSON.stringify(arr))
console.log(arr1)
/*
0: 1
1: 2
2: {name: "kole", age: null, sex: ""}
3: null
length: 4
__proto__: Array(0)
*/- 手写递归
js
function deepClone(obj) {
if(obj == null || typeof obj !== 'object') {
return obj
}
// 初始化返回结果
let newObj
if(obj instanceof Array) {
newObj = []
} else {
newObj = {}
}
for(let key in obj) {
// 保证key不是原型属性
if(obj.hasOwnProperty(key)) {
// 递归调用
newObj[key] = deepClone(obj[key])
}
}
return newObj
}