1、深浅拷贝
我们了解到对象(引用)类型在赋值的过程中其实是复制了地址,从而会导致改变了一方其他也都被改变的情况。通常在开发中我们不希望出现这样的问题。
let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2 希望是1
let a = {
name: 'xxx',
obj: {
aa: 3
}
}
let b = a
a.obj.aa = 5
console.log(b.obj.aa) // 5 希望是3
1)浅拷贝
如果我们要复制对象的所有属性都不是引用类型时,就可以使用浅拷贝,实现方式就是遍历并复制,最后返回新的对象。
function shallowCopy(obj) {
var copy = {};
// 只复制可遍历的属性
for (key in obj) {
// 只复制本身拥有的属性
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key];
}
}
return copy;
}
let a = {
age: 1
}
let b = shallowCopy(a)
a.age = 2
console.log(b.age) // 1
JS内部实现了浅拷贝,如Object.assign(target, source)
,其中第一个参数是我们最终复制的目标对象,后面的所有参数是我们的即将复制的源对象,支持对象或数组,一般调用的方式为
var newObj = Object.assign({}, originObj);
2)深拷贝
其实深拷贝可以拆分成 2 步,浅拷贝 + 递归,浅拷贝时判断属性值是否是对象,如果是对象就进行递归操作,两个一结合就实现了深拷贝。
1、简单实现
function cloneDeep(source) {
var target = {};
for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (typeof source[key] === 'object') { //问题一 typeof null === 'object' 传入null 会返回{} 应该返回 null
// 问题二 数组会转成对象 [1,2] 会变成 {0: 1, 1: 2}
target[key] = cloneDeep(source[key]); // 注意这里
} else {
target[key] = source[key];
}
}
}
return target;
}
let a = {
name: 'xxx',
obj: {
aa: 3
}
}
let b = cloneDeep(a)
a.obj.aa = 5
console.log(b.obj.aa) // 3
一个简单的深拷贝就完成了,但是这个实现还存在很多问题。
-
1、因为
typeof null === 'object'
,传入null
时应该返回null
而不是{}
-
2、没有考虑数组的兼容, 传入 [1,2 ]时 应该返回 [1,2] 而不是 {0:1, 1:2}
2、:解决以上两个问题
function cloneDeep2(source) {
if (!isObject(source)) return source; // 非对象返回自身
// if(source === null) return null
//解决数组兼容
var target = Array.isArray(source) ? [] : {};
for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep2(source[key]); // 注意这里
} else {
target[key] = source[key];
}
}
}
return target;
}
// 解决typeof null === 'object'
function isObject(obj) {
return typeof obj === 'object' && obj != null;
}
3、
function deepClone(source) { //递归拷贝
if(source === null) return null; //null 的情况
if(source instanceof RegExp) return new RegExp(source);
if(source instanceof Date) return new Date(source);
if(typeof source !== 'object') {
//如果不是复杂数据类型,直接返回
return source;
}
//解决数组兼容
var target = Array.isArray(source) ? [] : {};
for(let key in source) {
//如果 source[key] 是复杂数据类型,递归
target[key] = deepClone(source[key]);
}
return target;
}
。。。