一、直接赋值
直接赋值将会改变基本数据类型和引用数据类型
const a = {
"name":'wyy',
source:[100,99,98],
hobby:"reading"
}
// 将b直接赋值给a
const b = a
b.source = [1, 2, 3]
console.log(a); //{ name: 'wyy', source: [ 1, 2, 3 ], hobby: 'reading' }
console.log(b); //{ name: 'wyy', source: [ 1, 2, 3 ], hobby: 'reading' }
二、浅拷贝的原理和实现
“自己创建一个新对象,来接收你重新复制或引用新对象的值。如果对象的属性是基本数据类型,复制的值就是基本数据类型的值给新对象;但如果属性的值是引用数据类型,复制的就是内存中的地址,如果其中一个对象改变了这个内存地址中的内容,另外一个对象肯定也受影响”
1. 实现浅拷贝的四种方法
- object.assign()
const a = {
'aaa':{
val:'1',
child:{
val:'little'
}
},
name:'bob'
}
const b = Object.assign({age:18},a)
b.name ='Alice'
b.aaa.val = '2'
// { age: 18, aaa: { val: '2', child: { val: 'little' } }, name: 'Alice' }
console.log(b);
// { aaa: { val: '2', child: { val: 'little' } }, name: 'bob' }
console.log(a);
- 扩展运算符
扩展运算符类似于object.assign
const a = {
'aaa':{
val:'1',
child:{
val:'little'
}
},
name:'bob',
symbpl: Symbol('n')
}
const b = {...a}
b.name ='Alice'
b.aaa.val = '2'
console.log(b);
console.log(a);
- concat拷贝数组,该方法仅用来实现数组的浅拷贝
const a = [1,2,3,4,5]
const b = a.concat()
// [ 1, 2, 3, 4, 1, 2, 3, 4, 5]
console.log(b);
// [ 1, 2, 3, 4, 5 ]
console.log(a);
- slice拷贝数组
const a = [1,2,3,4,5]
const b = a.slice(1,3)
// 返回一个新的数组
// [ 2, 3 ]
console.log(b);
// [ 1, 2, 3, 4, 5 ]
console.log(a);
2. 手写实现浅拷贝
思路:
- 对基本类型做一个最基本的copy
- 对引用类型开辟新的存储空间
const shallowCopy = (target)=>{
if(typeof target === 'object'&& target !== null){
const cloneTarget = target.isArray()?[]:{}
for(let prop in target){
if(target.hasPrototype(prop)){
cloneTarget[prop] = target[prop]
}
}
return cloneTarget
}else{
return target
}
}
3. 浅拷贝特性
- 不会拷贝对象的继承属性
- 不能实现嵌套拷贝
- 可以拷贝symbol类型的属性
三、深拷贝的原理以及实现
“将一个对象从内存中完整地拷贝出来一份给目标对象,并从堆内存中开辟一个全新的空间存放新对象,且新对象的修改并不会改变原对象,二者实现真正的分离”
- json.stringfy()(乞丐版,存在较多问题)
1.拷贝date会变成字符串
2.键值对消失,拷贝函数,undifined,symbol时
3.无法拷贝原型链
4.无法拷贝循环引用
5.无法拷贝不可枚举类型
6.拷贝正则会变成空对象
- 递归实现深拷贝
思路:
1. 针对能够遍历对象的不可枚举类型属性以及symbol类型,使用Reflect.ownKeys方法。
2. 当参数为Date.RegExp类型,则直接生成一个新的实例返回。
3.利用object的getOwnPropertyDescriptors方法可以获得对象的所有属性,以及对应的特性,顺便结合Object的create方法创建一个新对象,并继承传入原对象的原型链。
4.利用WeakMap类型作为Hash表,因为WeakMap是引用类型,可以有效防止内存泄漏,作为检测循环引用很有帮助,如果存在循环,则引用直接返回WeakMap存储的值。
未实现手写深拷贝