浅拷贝和深拷贝浅析

参考 https://www.fly63.com/article/detial/9650

浅拷贝

只复制对象的第一层属性,如果对象的属性值是引用类型,则复制的是其引用地址。

初始化数据

let arr = [0, 1, [2, 3], 4];
let obj = { a: 1, b: { c: 2 }, d: () => 0 };
1. for 循环
function shallowClone(data) {
    let res = Array.isArray(data) ? [] : {};
    for (let k in data) res[k] = data[k];
    return res;
}
let copy = shallowClone(arr);
console.log(copy); // [ 0, 1, [ 2, 3 ], 4 ]
copy[0] = 6;
copy[2][0] = 8;
console.log(arr); // [ 0, 1, [ 8, 3 ], 4 ]
console.log(copy); // [ 6, 1, [ 8, 3 ], 4 ]
2. Object.assign()
function shallowClone(data) {
    return Object.assign({}, data);
}
let copy = shallowClone(obj);
console.log(copy, copy.d()); // { a: 1, b: { c: 2 }, d: [Function: d] } 0
copy.a = 6;
copy.d = () => 1;
copy.b.c = 8;
console.log(obj); // { a: 1, b: { c: 8 }, d: [Function: d] }
console.log(copy, copy.d()); // { a: 6, b: { c: 8 }, d: [Function (anonymous)] } 1
3. Object.create()
function shallowClone(data) {
    let res = Object.create(Object.getPrototypeOf(data));
    let names = Object.getOwnPropertyNames(data); // [ 'a', 'b', 'd' ]
    for (let key of names) {
        let val = Object.getOwnPropertyDescriptor(obj, key);
        Object.defineProperty(res, key, val);
    }
    return res;
}
4. 扩展运算符 …
function shallowClone(data) {
    return [...arr];
}
5. slice()
function shallowClone(data) {
    return data.slice();
}
6. concat()
function shallowClone(data) {
    return [].concat(data);
}
7. Array.from()
function shallowClone(data) {
    return Array.from(data);
}

深拷贝

复制对象及其所有子对象,确保新旧对象及其内部的所有引用类型都不共享任何数据。

1. JSON.parse(JSON.stringify())

局限性:

  • 只能处理Number,String,Boolean,Array,扁平对象。无法处理undefined、函数、循环引用等。
  • 会丢失原对象的 constructor,无论原对象的构造函数如何定义,拷贝后的 constructor 都为 Object。
function deepClone(data) {
    return JSON.parse(JSON.stringify(data));
}
let copy = deepClone(arr);
console.log(copy); // [ 0, 1, [ 2, 3 ], 4 ]
copy[0] = 6;
copy[2][0] = 8;
console.log(arr); // [ 0, 1, [ 2, 3 ], 4 ]
console.log(copy); // [ 6, 1, [ 8, 3 ], 4 ]

copy = deepClone(obj);
console.log(copy); // { a: 1, b: { c: 2 } }
copy.a = 6;
copy.d = () => 1;
copy.b.c = 8;
console.log(obj); // { a: 1, b: { c: 8 }, d: [Function: d] }
console.log(copy, copy.d()); // { a: 6, b: { c: 8 }, d: [Function (anonymous)] } 1
2. 递归拷贝(较完美的深拷贝)
/**
 * 判断是否是基本数据类型
 * @param value
 */
function isPrimitive(value) {
    return (
        typeof value === "string" ||
        typeof value === "number" ||
        typeof value === "symbol" ||
        typeof value === "boolean"
    );
}

/**
 * 判断是否是一个js对象
 * @param value
 */
function isObject(value) {
    return Object.prototype.toString.call(value) === "[object Object]";
}

/**
 * 深拷贝一个值
 * @param value
 */
function deepClone(value) {
    // 记录被拷贝的值,避免循环引用的出现
    let memo = {};
    function baseClone(value) {
        let res;
        // 如果是基本数据类型,则直接返回
        if (isPrimitive(value)) return value;
        // 如果是引用数据类型,我们浅拷贝一个新值来代替原来的值
        else if (Array.isArray(value)) res = [...value];
        else if (isObject(value)) res = { ...value };
        // 检测我们浅拷贝的这个对象的属性值有没有是引用数据类型。如果是,则递归拷贝
        Reflect.ownKeys(res).forEach((key) => {
            if (typeof res[key] === "object" && res[key] !== null) {
                //此处我们用memo来记录已经被拷贝过的引用地址。以此来解决循环引用的问题
                if (memo[res[key]]) res[key] = memo[res[key]];
                else {
                    memo[res[key]] = res[key];
                    res[key] = baseClone(res[key]);
                }
            }
        });
        return res;
    }
    return baseClone(value);
}
let copy = deepClone(arr);
console.log(copy); // [ 0, 1, [ 2, 3 ], 4 ]
copy[0] = 6;
copy[2][0] = 8;
console.log(arr); // [ 0, 1, [ 2, 3 ], 4 ]
console.log(copy); // [ 6, 1, [ 8, 3 ], 4 ]

copy = deepClone(obj);
console.log(copy); // { a: 1, b: { c: 8 }, d: [Function: d] }
copy.a = 6;
copy.d = () => 1;
copy.b.c = 8;
console.log(obj); // { a: 1, b: { c: 8 }, d: [Function: d] }
console.log(copy, copy.d()); // { a: 6, b: { c: 8 }, d: [Function (anonymous)] } 1
3. lodash 插件 cloneDeep()
const _ = require('lodash');
let copy= _.cloneDeep(obj);

相关推荐

  1. 拷贝拷贝浅析

    2024-07-12 10:12:03       24 阅读
  2. 拷贝拷贝

    2024-07-12 10:12:03       37 阅读
  3. 拷贝拷贝

    2024-07-12 10:12:03       32 阅读
  4. 讲清楚拷贝拷贝

    2024-07-12 10:12:03       62 阅读
  5. python拷贝拷贝

    2024-07-12 10:12:03       35 阅读
  6. 什么是拷贝拷贝

    2024-07-12 10:12:03       44 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 10:12:03       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 10:12:03       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 10:12:03       57 阅读
  4. Python语言-面向对象

    2024-07-12 10:12:03       68 阅读

热门阅读

  1. easyX的基本绘制使用案例

    2024-07-12 10:12:03       25 阅读
  2. 基于gunicorn+flask+docker模型高并发部署

    2024-07-12 10:12:03       24 阅读
  3. 高级IO_多路转接之ET模式Reactor

    2024-07-12 10:12:03       16 阅读
  4. 递归生成对象

    2024-07-12 10:12:03       24 阅读