1.数据的浅拷贝
let obj = {
a: 1,
b: 2,
c: {
d: 99
}
};
若要拷贝当前obj,可以使用for循环依次复制其键值,也可以使用扩展运算符。
let newObj = {
...obj
};
newObj.c.d = 100;
console.log(obj); //{ a: 1, b: 2, c: { d: 100 } }
拷贝后的值应与旧值无关,若扔存在关联则是浅拷贝。这里对新值进行修改,旧值也发生了改变,表明在复制obj时,将c属性的对象引用地址也拷贝过去了,造成了新值对旧值的引用地址修改。
这里可以再看一下数组的操作:
let arr = [1, 2, 3, [4]];
let newArr = arr.slice(0)
newArr[3][0] = 100;
console.log(arr); //[ 1, 2, 3, [ 100 ] ]
通过slice方法将arr的值全部截取,并赋值给newArr。这里对新值的数组元素进行操作,也影响到了旧值,因此slice做到的是也是浅拷贝。
2.实现深拷贝
那么,我们如何实现深拷贝呢?
1.对当前数据类型进行校验2.数据的循环引用问题
以上两点是数据深拷贝的实现思路,首先需要对数据的类型进行判断,常见的判断方法有:
typeof
Object.prototype.toString.call
instanceof
constructor
如果是基本数据类型(number,string,boolean,null,undefined)时,可以直接将值进行返回;
这里要提到null和undefined的类型校验,可参看视频内容。
如果是函数类型(function)时,可以直接将该函数返回,因为函数一般以调用为主,将函数转为字符串复制一遍再返回仍旧是这个函数;
如果是内置对象实例,则根据其类新建对应的对象返回即可;
例如:RegExp,Date等
如果是数组或对象等引用类型,则根据其构造函数新建对应的值返回即可。
({}).constructor //[Function: Object]([]).constructor //[Function: Array]
根据其构造函数可以直接new新值,创建新的值后,新值与旧值完全无关,这时通过循环旧值的索引或键,将值依次赋值到新值上去即可。
附方法源码:
function deepClone(value) {
if (value == undefined) return value;
if (typeof value !== 'object') return value;
if (value instanceof RegExp) return new RegExp(value);
if (value instanceof Date) return new Date(value);
let instance = new value.constructor;
for (let key in value) {
if (value.hasOwnProperty(key)) { //只拷贝私有属性
instance[key] = deepClone(value[key]);
}
}
return instance;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。