JavaScript之深拷贝

为什么要深拷贝?

JavaScript存储对象都是存地址的,所以浅拷贝会导致obj1和obj2指向同一块内存地址。改变其中一方的内容,都是在原来的内存上做修改,导致拷贝对象和源对象都发生改变,而深拷贝是开辟一块新的内存地址,将源对象的各个属性逐个复制进去。对拷贝对象和源对象各自的操作互不影响。
 

如何实现深拷贝

利用JSON.parse(JSON.stringify())

JSON.parse(JSON.stringify())实现深拷贝,其原理就是利用JSON。Stringify将js对象序列化,再反序列化还原对象。序列化的作用是存储(对象本身存储的只是一个地址映射,如果断电,对象将不复存在,因此需将对象的内容转换成字符串的形式再保存在磁盘上)和传输。

弊端:
1.如果obj里面有时间对象,用其处理后,返回的只是字符串形式的数据。
2.如果obj里有RegExp、Error对象,则序列化的结果会变成空对象。
3.如果obj里有函数、undefined,则序列化的结果会把函数或undefined丢失。
4.如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
5.JSON.stringify只能序列化可枚举的自由属性,例如:如果obj中的对象是由构造函数生成的,则实行深拷贝后,会丢失对象的constructor;
6.如果对象中存在循环引用的情况也无法正确实现深拷贝

 

利用递归的方式实现深拷贝

//使用递归的方式实现数组、对象的深拷贝
function deepClone1(obj) {
	//判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
	var objClone = Array.isArray(obj) ? [] : {};
	//进行深拷贝的不能为空,并且是对象或者是
	if (obj && typeof obj === "object") {
		for (key in obj) {
			if (obj.hasOwnProperty(key)) {
				if (obj[key] && typeof obj[key] === "object") {
					objClone[key] = deepClone1(obj[key]);
				} else {
					objClone[key] = obj[key];
				}
			}
		}
	}
	return objClone;
}

 

利用Jquery的extend方式实现深拷贝

var $ = require('jquery');
var newObj = $.extend(true, {}, obj);

通过loadsh.CloneDeep()方法实现拷贝

var _ = require('lodash');
var newObj = _.cloneDeep(obj);

通过Object.assign()拷贝

function assignDeep(target, ...sources) {
    // 1. 参数校验
    if (target == null) {
        throw new TypeError('Cannot convert undefined or null to object');
    }

    // 2. 如果是基本类型数据转为包装对象
    let result = Object(target);
    
    // 3. 缓存已拷贝过的对象,解决引用关系丢失问题
    if (!result['__hash__']) {
        result['__hash__'] = new WeakMap();
    }
    let hash  = result['__hash__'];

    sources.forEach(v => {
        // 4. 如果是基本类型数据转为对象类型
        let source = Object(v);
        // 5. 遍历原对象属性,基本类型则值拷贝,对象类型则递归遍历
        Reflect.ownKeys(source).forEach(key => {
            // 6. 跳过自有的不可枚举的属性
            if (!Object.getOwnPropertyDescriptor(source, key).enumerable) {
                return;
            }
            if (typeof source[key] === 'object' && source[key] !== null) {
                // 7. 属性的冲突处理和拷贝处理
                let isPropertyDone = false;
                if (!result[key] || !(typeof result[key] === 'object') 
                    || Array.isArray(result[key]) !== Array.isArray(source[key])) {
                    // 当 target 没有该属性,或者属性类型和 source 不一致时,直接整个覆盖
                    if (hash.get(source[key])) {
                        result[key] = hash.get(source[key]);
                        isPropertyDone = true;
                    } else {
                        result[key] = Array.isArray(source[key]) ? [] : {};
                        hash.set(source[key], result[key]);
                    }
                }
                if (!isPropertyDone) {
                    result[key]['__hash__'] = hash;
                    assignDeep(result[key], source[key]);
                }
            } else {
                Object.assign(result, {[key]: source[key]});
            }
        });
    });

    delete result['__hash__'];
    return result;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值