# 深浅拷贝 深拷贝

复制对象没有保持和原对象一样的结构。因此，JSON 实现深复制不能处理指向相同引用的情况，相同的引用会被重复复制。

* JSON.parse(JSON.stringify(data))

如果对象中存在循环引用的情况也无法正确实现深拷贝

如果 data 里面有时间对象， 则 JSON.stringify 后再 JSON.parse 的结果， 时间将只是字符串的形式，而不是时间对象

如果 data 里有函数, 则序列的结果会把函数置为 undefined

无法拷贝 copyObj 对象原型链上的属性和方法；

取不到值为 undefined 的 key；

如果对象里有函数，函数无法被拷贝下来

递归实现 JS 原生的方法不能很好的实现深复制，那么我们就动手实现一个。

思想非常简单：对于简单类型，直接复制。对于引用类型，递归复制它的每一个属性。

我们需要解决的问题：

* 循环引用
* 相同引用

### 解决循环引用问题

考虑 WeakMap

但是 WeakMap 比 Map 有两个不同：

1、【特殊点】WeakMap 只接受引用类型（对象）作为键名； 2、【优点】WeakMap 的键名所指向的对象都是弱引用，不计入垃圾回收机制，不用考虑内存泄漏。 当引用对象被清除，其所对应的 WeakMap 记录就会自动被移除。

## 实现 一个浅克隆

```js
const shallClone = (target) => {
  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;
  }
};
```

## 实现一个 深克隆

```js
/**
 * 深克隆（深拷贝）+ 解决深拷贝函数中循环引用时导致的栈溢出的问题
 * @param {object} origin
 * @param {*} hashMap WeakMap数据，用于缓存克隆过的对象
 * @returns origin / 克隆的origin
 */
function deepCloneCycle(origin, hashMap = new WeakMap()) {
  let result = null;
  if (hashMap.has(origin)) return hashMap.get(origin); // 查缓存字典中是否已有需要克隆的对象，有的话直接返回同一个对象（同一个引用，不用递归无限创建进而导致栈溢出了）;
  // typeof null === 'object' true
  // typeof [] === 'object' true
  // typeof NaN === 'object' false
  if (typeof origin === "object" && origin !== null) {
    // 【类型判断】引用类型，进行递归拷贝（用typeof判断类型要剔除null的情况）
    if (Object.prototype.toString.call(origin) === "[object Array]") {
      // 【类型判断】数组类型，创建一个新数组
      result = [];
      hashMap.set(origin, result); // 哈希表缓存新值
      // 【遍历赋值】
      origin.forEach((el) => {
        result.push(deepCloneCycle(el, hashMap)); // 【递归】
      });
    } else if (Object.prototype.toString.call(origin) === "[object Object]") {
      // 【类型判断】对象类型，创建一个新对象
      result = {};
      hashMap.set(origin, result); // 哈希表缓存新值
      for (const key in origin) {
        // 【遍历赋值】对象这里特殊处理了，不遍历拷贝原型链上的属性
        if (origin.hasOwnProperty(key)) {
          result[key] = deepCloneCycle(origin[key], hashMap); // 【递归】
        }
      }
    }
  } else {
    // 【类型判断】原始类型直接返回
    return origin;
  }
  return result;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shenjunhong.gitbook.io/blog/yuan-ma/yuan-ma-shou-xie-xi-lie/shen-qian-kao-bei.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
