浅拷贝和深拷贝浅析

参考 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);
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中,可以使用copy模块中的deepcopy方法来实现列表的深拷贝深拷贝会创建一个完全独立的列表副本,无论多少层嵌套,得到的新列表都是和原来无关的。可以通过引入copy模块,并使用copy.deepcopy()来进行深拷贝操作。例如: import copy old = [1,[1,2,3],3] new = copy.deepcopy(old) 在上述代码中,old是原始列表,new是深拷贝得到的新列表。无论对new进行任何修改,都不会影响到old的值。这种方法是最安全、最清爽、最有效的深拷贝方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [深入浅析Python中list的复制及深拷贝浅拷贝](https://download.csdn.net/download/weixin_38643269/12867045)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Python中列表List的复制(直接复制、浅拷贝深拷贝)](https://blog.csdn.net/weixin_49899130/article/details/129380610)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值