深拷贝和浅拷贝是只针对Object和Array引用类型的,为什么这么说呢,要理解深拷贝与先拷贝,首先我们要搞懂数据类型的存储方式
数据类型
数据类型分为基本数据类型和引用数据类型
- 基本数据类型:String,Number,Boolean,Null,Undefined
- 引用数据类型:Object
这两种类型存储方式的区别
基本类型数据直接存储在栈内,而引用型数据类型是在栈中存放指针,通过指针指向,在堆中找到真实的数据内容,所以说深拷贝和浅拷贝只针对与引用类型
浅拷贝
对于浅拷贝而言,只是单单拷贝了对象的引用,新的对象与原有对象,同时指向同一个堆内存空间,若数据内容改变,新老对象一起发生变化
深拷贝
而我们开发过程中浅拷贝并不能满足我们需求,由此,深拷贝出现了,深拷贝会将原有数据的引用和数据内容一并拷贝,形成一个新的引用对象
深拷贝的实线
上面我们理解了深浅拷贝的原理,那如何做到实现呢,下面例举一些常用的实现方法
1、JSON.stringify()以及JSON.parse()
var obj1 = {
name: 'Echo',
age: 16
}
var obj2 = JSON.parse(JSON.stringify(obj1)) // 将obj1深拷贝
obj2.name = 'Kim' // 改变新对象的值
console.log(obj1) // {name: 'Echo', age: 16}
console.log(obj2) // {name: 'Kim', age: 16}
注意:这种实现是存在局限性的,这种深拷贝是通过JSON.stringify(value)和JSON.parse(value)实现的,value不能为空,所以如果是Undefined,Function,RegExp,Error序列化只能得到空对象,就不适用了
eg:
var obj1 = {
name: 'Echo',
function(){
console.log('深拷贝')
},
undefined
}
var obj2 = JSON.parse(JSON.stringify(obj1)) // 将obj1深拷贝
console.log(obj1) // {name: "echo", function: ƒ, undefined: undefined}
console.log(obj2) // {name: 'echo'}
2、Object.assign(target, source)
var obj1 = {
name: 'Echo',
age: 16
}
var obj2 = Object.assign ({}, obj1) // 将obj1深拷贝
obj2.age = 18 // 改变新对象的值
console.log(obj1) // {name: 'Echo', age: 16}
console.log(obj2) // {name: 'Echo', age: 18}
注意:这种实现也是存在局限性的,如果原对象中含有多层嵌套对象结构,则高层结构仅仅是浅拷贝
eg:
var obj1 = {
name: 'Echo',
age: 16,
arr: [1, 2, 3]
}
var obj2 = Object.assign ({}, obj1) // 将obj1深拷贝
obj2.arr[0] = 18 // 改变新对象的值
console.log(obj1.arr) // [18, 2, 3]
console.log(obj2.arr) // [18, 2, 3]
3、手写递归方法
// 定义一个深拷贝函数 接收目标target参数
function deepClone(target) {
// 定义一个变量
let result;
// 如果当前需要深拷贝的是一个对象的话
if (typeof target === 'object') {
// 如果是一个数组的话
if (Array.isArray(target)) {
result = []; // 将result赋值为一个数组,并且执行遍历
for (let i in target) {
// 递归克隆数组中的每一项
result.push(deepClone(target[i]))
}
// 判断如果当前的值是null的话;直接赋值为null
} else if(target===null) {
result = null;
// 判断如果当前的值是一个RegExp对象的话,直接赋值
} else if(target.constructor===RegExp){
result = target;
}else {
// 否则是普通对象,直接for in循环,递归赋值对象的所有值
result = {};
for (let i in target) {
result[i] = deepClone(target[i]);
}
}
// 如果不是对象的话,就是基本数据类型,那么直接赋值
} else {
result = target;
}
// 返回最终结果
return result;
}