原生Javascript深拷贝
深拷贝函数
实现代码可以直接复制,解析在下方
/**
* @parma {Object|Array} obj
* @return {Object|Array}
* 返回一个新的引用类型实现深拷贝
**/
function deepCopy(obj) {
if (typeof obj !== 'object') return obj
var target = Array.isArray(obj) ? [] : {}
for (var key in obj) {
target[key] = obj[key]
if (typeof obj[key] == 'object') {
target[key] = deepCopy(obj[key])
}
}
return target
}
浅拷贝和深拷贝
浅拷贝
-
简单数据类型的赋值是在栈内开辟内存,直接存值
-
复杂数据类型(引用类型)的赋值是在栈内留下地址,在堆内储存数据
-
只在栈内实现
-
复杂类型直接把一个变量赋给另一个变量时,只会把变量存的地址赋给另一个变量
-
则浅拷贝是指复杂数据类型在赋值时,只把地址赋值给变量,两个变量都指向同一个堆里的数据,变量a的值改变,变量b的值也发生改变。这样具体实际应用意义不大,变量a,b都是同一个对象,那么用一个变量不就好了
-
深拷贝
- 把对象(数组或复杂类型)a内的属性和值 一一遍历赋给变量b,如果对象a,其中某一属性的值是复杂类型则继续遍历此属性中的对象并赋值
var obj = {
uname : '小明',
age : 18,
father : {
uname : '爸爸',
age : 48,
wife:{
uname:'妈妈',
...
}
}
}
var newObj = {}
newObj.uname = '小明'
newObj.age = 18
newObj.father = {}
newObj.father.uname = '爸爸'
newObj.father.age = 48
newObj.father.wife = {}
newObj.father.wife.uanem = '妈妈'
...
暴力拷贝
function deepCloen(obj) {
// 当前循环的对象
var cur = {}
// obj为被循环的对象
for (var key in obj) {
if (typeof obj[key] === 'object') {
cur[key] = deepCloen(obj[key])
} else {
cur[key] = obj[key]
}
}
// 开始向上返回结果
return cur
}
思路:创建空对象,判断当前循环是不是复杂类型,是的话则调用方法本身再次循环判断,如果是简单类型直接赋值,如果for in 循环结束遍历,说明本次所有结果都是简单类型,开始向上返回结果
方法缺点:如果是数组的话,也会被改为对象,简单但是不好用
实现深拷贝
/**
* @parma {Object|Array} obj
* @return {Object|Array}
* 返回一个新的引用类型实现深拷贝
**/
function deepCopy(obj) {
// 简单类型直接返回
if (typeof obj !== 'object') return obj
// 判断是数组还是对象
var flag = Array.isArray(obj)
// 当前循环的引用类型
var cur = flag ? [] : {}
for (var key in obj) {
// if结构优化,先赋值,如果这次是对象,重新赋值
cur[key] = obj[key]
if (typeof obj[key] == 'object') {
cur[key] = deepCopy(obj[key])
}
}
// 循环到最后时开始向上返回值,把每次的结果
return cur
}
思路:在暴力拷贝的基础上多了判断,flag作为判断标致,控制创建对象还是数组,并且for in循环也能拷贝数组
测试
var obj = {
uname: '孙悟空',
team: {
master: '唐僧',
shenxian: undefined,
bros: [{ uname: '八戒', hobbit: 'eat' }, '沙僧', '小白龙']
}
}
function deepCopy(obj) {
var flag = Array.isArray(obj)
var target = flag ? [] : {}
for (var key in obj) {
target[key] = obj[key]
if (typeof obj[key] == 'object') {
target[key] = deepCopy(obj[key])
}
}
return target
}
// 测试
var myObj = deepCloen(swk)
console.log(myObj)
obj.team.bros[1] = '悟净'
obj.team.bros[0].hobbit = 'sleep'
console.log(obj);
- 如果改变原对象obj的值,新对象myObj不会改变,说明深度拷贝实现
借助工具轻松实现
1.JSON newObj=JSON.parse(JSON.stringify(obj))
// 不能识别undefined
2.jQuery $.extend(true,newObj,obj)
// 不能识别undefined
3.lodash newObj=_.cloneDeep(obj)