一、如何区分深拷贝和浅拷贝
1.图示区分:
2.代码区分:
(1)浅拷贝示例:
let family = {
age: 32,
name: 'yorick',
children: [
{
age: 3,
name: 'moon'
},
{
age: 1,
name: 'flower'
}
]
};
let family1 = family;
family1.name = 'jack';
family1.children[0] = {
age: 10,
name: 'lily'
};
console.log("family.name", family.name);
// yorick
console.log("family.children[0]", family.children[0]);
/*
{
age: 10,
name: 'lily'
}
*/
console.log("family1.name", family1.name);
// jack
console.log("family1.children[0]", family1.children[0]);
/*
{
age: 10,
name: 'lily'
}
*/
(2)浅拷贝的含义:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
// 浅拷贝的实现方法
const shallowClone = sourceObj => {
const targetObj = {};
for(let i in sourceObj) {
if (sourceObj.hasOwnProperty(i)) {
targetObj[i] = sourceObj[i];
}
}
return targetObj;
}
(3)深拷贝的示例:
let family = {
age: 32,
name: 'yorick',
children: [
{
age: 3,
name: 'moon'
},
{
age: 1,
name: 'flower'
}
]
};
const deepClone = sourceObj => {
// 处理一些异常输入
if (sourceObj === null) return sourceObj;
if (sourceObj instanceof RegExp) return new RegExp(sourceObj);
if (sourceObj instanceof Date) return new Date(sourceObj);
if (typeof sourceObj !== "object") return sourceObj;
// 递归法实现深拷贝
let targetObj = new sourceObj.constructor();
for (let key in sourceObj) {
if (sourceObj.hasOwnProperty(key)) {
// 实现一个递归拷贝
targetObj[key] = deepClone(sourceObj[key]);
}
}
return targetObj;
}
let family1 = deepClone(family);
family1.name = 'jack';
family1.children[0] = {
age: 10,
name: 'lily'
};
console.log("family.name", family.name);
// yorick
console.log("family.children[0]", family.children[0]);
/*
{
age: 3,
name: 'moon'
}
*/
console.log("family1.name", family1.name);
// jack
console.log("family1.children[0]", family1.children[0]);
/*
{
age: 10,
name: 'lily'
}
*/
(4)深拷贝的含义:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
// 深拷贝的递归实现方法
const deepClone = sourceObj => {
// 处理一些异常输入
if (sourceObj === null) return sourceObj;
if (sourceObj instanceof RegExp) return new RegExp(sourceObj);
if (sourceObj instanceof Date) return new Date(sourceObj);
if (typeof sourceObj !== "object") return sourceObj;
// 递归法实现深拷贝
let targetObj = new sourceObj.constructor();
for (let key in sourceObj) {
if (sourceObj.hasOwnProperty(key)) {
// 实现一个递归拷贝
targetObj[key] = deepClone(sourceObj[key]);
}
}
return targetObj;
}
(5)关于对象赋值操作与深浅拷贝的区别:当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
二、浅拷贝和深拷贝的一些常见实现方式
1.浅拷贝的实现方式:
(1)Object.assign()
划重点:面试常常问到这个问题,Object.assign()方法是可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
(2)展开运算符...
这两个就合并举例了
let family = {
age: 32,
name: 'yorick',
children: [
{
age: 3,
name: 'moon'
},
{
age: 1,
name: 'flower'
}
]
};
let family1 = {
age: 28,
name: 'jason',
children: [
{
age: 5,
name: 'amy'
}
]
};
// 效果一样,都是浅拷贝
const newFamily1 = {...family, ...family1};
const newFamily2 = Object.assign({}, family, family1);
(3)函数库lodash的_.clone方法
var _ = require('lodash');
let family = {
age: 32,
name: 'yorick',
children: [
{
age: 3,
name: 'moon'
},
{
age: 1,
name: 'flower'
}
]
};
var family1 = _.clone(family);
var family2 = _.cloneDeep(family);
console.log(family.children[0].age === family1.children[0].age); // true
console.log(family.children[0].age === family2.children[0].age); // false
2.深拷贝的实现方式:
(1) JSON.parse(JSON.stringify())
(2)函数库lodash的_.cloneDeep方法
这个例子放在上边了。
(3)jQuery.extend()方法
//第一个参数为true,就是深拷贝
$.extend(isDeepCopy, target, object1, [objectN])
(4)手写递归方法,上边已经提供,不再赘述。
后记:以上的深拷贝方法都有一些局限性,(1)解决不了循环引用的问题,(2)(3),如果你做的是比较新的前端项目,有可能不会引入这两个库,个人目前在项目中用的是(4)的方法,但是这种方法针对大对象是否有优化空间是个值得思考的问题,当我在项目中实践以后会分享出来的。