# 深拷贝

# 介绍

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

# 存储

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

# 深拷贝

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

# 实现方案

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

  2. 递归实现:

    ```javascript
    function deepCopy(obj, parent = null) {
        // 创建一个新对象
        let result = {};
        let keys = Object.keys(obj),
            key = null,
            temp = null,
            _parent = parent;
        // 该字段有父级则需要追溯该字段的父级
        while (_parent) {
            // 如果该字段引用了它的父级则为循环引用
            if (_parent.originalParent === obj) {
                // 循环引用直接返回同级的新对象
                return _parent.currentParent;
            }
            _parent = _parent.parent;
        }
        for (let i = 0; i < keys.length; i++) {
            key = keys[i];
            temp = obj[key];
            // 如果字段的值也是一个对象
            if (temp && typeof temp === 'object') {
                // 递归执行深拷贝 将同级的待拷贝对象与新对象传递给 parent 方便追溯循环引用
                result[key] = DeepCopy(temp, {
                    originalParent: obj,
                    currentParent: result,
                    parent: parent
                });
            } else {
                result[key] = temp;
            }
        }
        return result;
    }
    ```
  3. 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)
    });
  4. H5 新增 structuredClone
    结构化克隆解决了该 JSON.stringify () 技术的许多(尽管不是全部)缺点。结构化克隆可以处理循环依赖,支持许多内置数据类型,并且更健壮且速度更快。
    但是,它仍然有一些限制:

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

# 浅拷贝实现方案

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

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

dmq 微信支付

微信支付

dmq 支付宝

支付宝