深拷贝和浅拷贝简单解释
浅拷贝和深拷贝都只针对于引用数据类型进行拷贝的,浅拷贝只复制指向某个对象的第一层,对于大于2层的,新旧对象还是共享同一块内存;但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,无论怎么修改新对象也不会影响原对象。
区别:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制;
浅拷贝的实现
方式一:Object.assign()方式
let obj1 = {
name: 'zhangsan',
age: 20,
hobby: {
like1: 'play basketball',
like2: 'travel'
}
};
let obj2 = Object.assign({}, obj1);
// 更改第一层
obj2.name = 'lisi';
obj2.hobby.like1 = "reading"
console.log(obj1, obj2)
方式二:用...的实现
let obj1 = {
name: 'zhangsan',
age: 20,
hobby: {
like1: 'play basketball',
like2: 'travel'
}
};
let obj2 = {
...obj1
}
// 更改第一层
obj2.name = 'lisi';
obj2.hobby.like1 = "reading"
console.log(obj1, obj2)
结果依旧如上图。
深拷贝的实现
JavaScript原生的方式
方式一:使用JSON.stringify和JSON.parse实现深拷贝:JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象;
代码:
function deepCopy(obj){
// 将引入的对象转化为字符串的形式
let obj1 = JSON.stringify(obj)
// 将obj1的字符串形式转化为对象
let obj2 = JSON.parse(obj1)
// 返回对象
return obj2
}
// 测试
let page = {
username: 'zhangsan',
week: [1, 2, 3, [4, 5], 6]
}
// 开始深拷贝
let newPage = deepCopy(page)
newPage.username = 'lisi'
newPage.week[3][1] = 100
console.log('page', page) // 未变
console.log('newPage', newPage)// 变化
看效果截图:
缺陷:它会抛弃对象的constructor,深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object;这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON;
方法二:递归实现深拷贝
代码:
function deepClone (obj) {
// 判断是否未对象类型,并且对象不为空和underfined,如果是就直接返回对象
if (typeof obj !== 'object' || obj == null) {
// 返回obj并跳出deepClone,一般返回的都是属性值
return obj
}
//初始化结果
let result
// instanceof使用用来判断引用类型中的数组和对象的
if(obj instanceof Array){
result = []
} else {
result = {}
}
// 对键值对的值做一个循环
// 虽然说上面的obj已经跳出去了这个函数,但是这个循环还是在继续的,递归仍在继续
for(let key in obj){
// hasOwnProperty来判断obj有没有原生属性key
if(obj.hasOwnProperty(key)){
// 递归调用,
//下面这种写法相当于result.key = deepClone(obj.key)的写法
result[key] = deepClone(obj[key])
}
}
//返回结果
return result
}
// 测试
const obj1 = {
age: '11',
username: 'qqq',
city: {
1: 'hangzhou',
2: 'shanghai'
},
portman: ['a','e','i','o','u'],
function () {
console.log('我是函数')
}
}
const obj2 = deepClone(obj1);
obj2.username='xx1x111111'
console.log('拷贝前obj1', obj1)
console.log('拷贝后obj2', obj2)
结果实现:
JQuery的方式
jquery 提供一个$.extend
可以用来做深拷贝(具体代码不做演示);
备注:slice()和concat()都并非深拷贝;