# 深拷贝

# 介绍

我们知道在 javascript 中有八种数据类型:其中 number,string,undefined,null,boolean,symbol 和 bigint 为基本数据类型,而 object 为复杂数据类型

# 存储

  • 对于基本数据类型,其值直接存储于栈中。
  • 对于复杂数据类型,其值存储于堆中,而栈中只存储堆中的地址。这样做的好处有:
    • 节省内存空间:存储在堆中的对象可以通过栈内的引用被访问和操作,意味着对象可以在不同的上下文中被共享和引用,从而节省内存。
    • 垃圾回收:堆内存中的对象不再被引用时,垃圾回收机制就会自动进行回收,从而避免了内存泄漏和资源浪费。
    • 动态分配内存:堆内存允许对象动态的增长和缩小,因此可以根据需要灵活地修改对象的结构和内容,使得 js 对象可以轻松地扩展以适应不同的应用需求。

# 深拷贝

而深拷贝和浅拷贝就是对于复杂数据类型 object 来说的,当拷贝了对象的一层(即堆的引用)时,就称之为浅拷贝,当拷贝了对象的两层(堆中创建新的对象)时,就称之为深拷贝。

# 实现方案

  1. JSON.parse(JSON.stringify(obj)) ,第一种方法是使用 JSON 方法,但是这个方法有一些限制:JSON 序列化时函数会被转为 null,正则表达式会被转为空对象。

  2. 递归实现:

// 是否是对象类型
const isObject = (obj) => typeof obj === 'object' || typeof obj === 'function' && obj !== null;
function deepClone(target,map = new WeakMap()) {
   if(map.get(target)) return target;
   let constructor = target.constructor; // 获取到 constructor
   // 如果是日期或者正则,就新创建一个实例
   if(/^(RegExp|Date)$/i.test(constructor.name)){
       return new constructor(target);
   }
   if(isObject(target)){
       map.set(target,true);
       const cloneTarget = Array.isArray(target) ? []:{};
       for(let prop in target){
           if(target.hasOwnProperty(prop)){
               cloneTarget[prop] = deepClone(target[prop],map);
           }
       }
       return cloneTarget;
   }else {
       return target;
   }
}
// > 注意:1、原型链不能形成闭环(报错),2、__proto__的值只能是对象或者 null,3、一个对象只能又一个 [[Prorotype]],4、__proto__是内部 [[Prototype]] 的 getter/setter。
  1. MessageChannel 实现深克隆:由于浏览器不能将一个函数正确的复制到另一个线程中,所以不能支持函数的深克隆。
function deepCopy(obj) {
    return new Promise((resolve) => {
    const {port1, port2} = new MessageChannel();
    port2.onmessage = ev => resolve(ev.data);
    port1.postMessage(obj);
    });
}
deepCopy(obj).then((copy) => {// 异步的
    let copyObj = copy;
    console.log(copyObj, obj)
    console.log(copyObj == obj)
});
  1. H5 新增 structuredClone
    结构化克隆解决了该 JSON.stringify () 技术的许多(尽管不是全部)缺点。结构化克隆可以处理循环依赖,支持许多内置数据类型,并且更健壮且速度更快。
    但是,它仍然有一些限制:

原型:如果你使用 structuredClone () 类实例,你将获得一个普通对象作为返回值,因为 structuredClone会丢弃对象的原型链
函数:如果你的 对象包含函数,它们将被悄悄丢弃
不可克隆: 有些值不是结构化可克隆的 ,尤其是 Error、 DOM 节点 和 Function。尝试这样做将引发 DataCloneError 异常。
属性描述符:setter 和 getter (以及类似元数据的功能) 不会被复制。例如,如果使用属性描述符将对象标记为只读,则复制后的对象中是可读写 (默认配置)。
RegExp: RegExp对象的lastIndex字段不会保留

# 浅拷贝实现方案

  1. Object.assign({},obj) ,第二方法是使用 Object.assign ()
  2. const obj1 = {...obj2} ,使用扩展运算符
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

dmq 微信支付

微信支付

dmq 支付宝

支付宝