if (typeof target === 'object' && target !== null) {
const cloneTarget = Array.isArray(target) ? []: {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = target[prop];
return cloneTarget;
} else {
return target;
};
4-2. 深拷贝
4-2-1. 定义
深拷贝复制一个完全相同的对象,从堆内存中开辟一个新的区域存放该对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
4-2-2. 代码实现
4-2-2.(1). JSON.stringify
原理:将一个对象序列化成为 JSON 的字符串,并将对象里面的内容转换成字符串,最后再用 JSON.parse() 的方法将JSON 字符串生成一个新的对象。
缺点:
原对象中的属性有函数、undefined、Symbol类型时,其键值对会消失。
拷贝 Date 引用类型会变成字符串。
无法拷贝不可枚举的属性。
无法拷贝对象的原型链。
拷贝 RegExp 引用类型会变成空对象。
对象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的结果会变成 null。
无法拷贝对象的循环应用,即对象成环 (obj[key] = obj)。
代码例子:
let source = { a:1, b:[1,2,3] }
let tempStr = JSON.stringify(source);
let target = JSON.parse(tempStr);
4-2-2.(2). 手撕递归实现
原理:通过 for in 遍历传入参数的属性值,如果值是引用类型则再次递归调用该函数,如果是基础数据类型就直接复制。
缺点:(同 JSON.stringify方案)
不能复制不可枚举的属性以及 Symbol 类型。
只是针对普通的引用类型的值做递归复制,而对于 Array、Date、RegExp、Error、Function 这样的引用类型并不能正确地拷贝。
对象的属性里面成环,即循环引用没有解决。
代码实现如下:
const deepClone = obj => {
let cloneObj = {}
for(let key in obj) {
if(typeof obj[key] ==='object') {
cloneObj[key] = deepClone(obj[key]);
} else {
cloneObj[key] = obj[key];
return cloneObj;
4-2-2.(3). 递归优化
原理:解决上一个方案的缺点
针对能够遍历对象的不可枚举属性以及 Symbol 类型,我们可以使用 Reflect.ownKeys 方法。
当参数为 Date、RegExp 类型,则直接生成一个新的实例返回。
利用 Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性,以及对应的特性,顺便结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链。
利用 WeakMap 类型作为 Hash 表,因为 WeakMap 是弱引用类型,可以有效防止内存泄漏(你可以关注一下 Map 和