浅拷贝
创建一个对象的复制,但是其中的元素都是原始对象的引用,所以只解决了第一层的拷贝。如果原始对象的元素变化,在浅拷贝中也会体现这些变化。
实现方式
前2种是同时支持对象和数组的拷贝:
实现方式1 (Object 方法)
| 12
 
 | const b = Object.assign({}, a);const c = Object.create(a);
 
 | 
实现方式2 (展开运算符)
| 12
 
 | const b = { ...a };const c = [...a];
 
 | 
以下是只针对数组的拷贝:
实现方式3 (Array.prototype.concat())
实现方式4 (Array.prototype.slice())
实现方式5 (Array.from())
| 1
 | const b = Array.from(a);
 | 
深拷贝
创建一个对象的全新复制,会递归地复制对象的所有元素和子元素。如果原始对象的元素变化,深拷贝创建的对象不受影响。
实现方式
实现方式1 (JSON 序列化):
| 1
 | const b = JSON.parse(JSON.stringify(a));
 | 
上述方法的局限性:
- 会忽略值为 undefined、symbol 或函数的属性
- 不支持循环引用,会直接报错实现方式2 (2022年新特性,core-js 已支持该 polyfill):| 12
 3
 4
 5
 6
 
 | const b = window.structuredClone(a);
 const arr = new Uint8Array();
 const c = window.structuredClone(arr, {
 transfer: [arr.buffer]
 })
 
 |  
 
- 支持循环引用
- 还是不支持序列化,含有值为 undefined、symbol 或函数的属性,会直接报错
实现方式3 (MessageChannel):
| 12
 3
 4
 5
 6
 7
 
 | const mySturcturedClone = (obj) => new Promise((resolve) => {const { port1, port2} = new MessageChannel();
 port2.onmessage = (ev) => resolve(ev.data);
 port1.postMessage(obj);
 });
 
 const b = await mySturcturedClone(a);
 
 | 
- 支持值为 undefined 的属性
- 支持循环引用
- 还是不支持 symbol 或函数的属性,会直接报错
实现方式4 (递归遍历):
```javascript
const myStructuredClone = (origin) => {
    const map = new WeakMap(); // 因为对象的 key 可能是对象,所以使用 WeakMap
    const deepClone = (obj) => {
        if (typeof obj !== ‘object’ || obj === null) return obj; // 基本类型直接返回
        if (map.has(obj)) return map.get(obj); // 防止循环引用
        const clone = Array.isArray(obj) ? [] : {}; // 判断是数组还是对象
        map.set(obj, clone);
        for (const key in obj) { // 同时可以遍历数组和对象,数组的 key 为索引
            // Object 是一个构造函数,所以要取 Object.prototype 对象上的方法
            if (Object.prototype.hasOwnProperty.call(obj, key)) { // 判断是否是自身属性,而不是原型链上的属性
                clone[key] = deepClone(obj[key]);
            }
        }
        return clone;
    }
    return deepClone(origin);
}