js深拷贝和浅拷贝

  1. 请说说你理解的JS中的深克隆和浅克隆?
    区别:
    浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,两个对象是联动的。

深拷贝:会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

实现:
深拷贝基础版(递归):

<script>
function deepCopy(obj,newObj){
	for(let key in obj){
		if(obj.hasOwnProperty(key)){
			let oldVal = obj[key];
			if(!(oldVal instanceof Object)){
				newObj[key] = oldVal
			}else{
				let temp = new oldVal.constructor;
				deepCopy(temp);
				newObj[key] = temp;
			}
		}
	}
}

let obj = {
	num : 10,
	str : 'string',
	arr : [1,2,3,4],
	arr2 : {a:'1'}
};

let newObj = {};
deepCopy(obj,newObj);

obj.arr[0] = 1000;
obj.arr2.a = '2';

console.log(newObj);//{arr: [],arr2: {},num: 10,str: "string"}
console.log(obj);//{arr: [1000, 2, 3, 4],arr2: {a: "2"},num: 10,str: "string"
</script>

完整版本:

<script>
//判断是否为复杂数据类型
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null);

//利用 WeekMap() 的键对自己所引用对象的引用都是弱引用的特性,在没有其他引用和该键引用同一对象的情况下,这个对象将会被垃圾回收
//为了解决循环引用的问题,设置一个哈希表存储已拷贝过的对象进行循环检测,当检测到当前对象已存在于哈希表中时,取出该值并返回即可
const deepClone = function(obj,hash = new WeakMap()){
	//查哈希表,防止循环拷贝。如果成环了(对象循环引用),参数obj = obj.loop = 最初的obj,则会在WeakMap中找到第一次放入的obj提前返回第一次放入WeakMap的cloneObj,解决对象循环引用的问题
	if(hash.has(obj)) return hash.get(obj);
	
	//如果参数为Date, RegExp, Set, Map, WeakMap, WeakSet等引用类型,则直接生成一个新的实例
	let type = [Date,RegExp,Set,Map,WeakMap,WeakSet];
	if(type.includes(obj.constructor)) return new obj.constructor(obj);

	//遍历传入参数所有属性描述符
	let allDesc = Object.getOwnPropertyDescriptors(obj);
	//继承原型
	let cloneObj = Object.create(Object.getPrototypeOf(obj),allDesc);
	
	 // 获取所有 Symbol 类型键
    let symKeys = Object.getOwnPropertySymbols(obj)
    // 拷贝 Symbol 类型键对应的属性
    if (symKeys.length > 0) {
        symKeys.forEach(symKey => {
            cloneObj[symKey] = isComplexDataType(obj[symKey]) ? deepClone(obj[symKey], hash) : obj[symKey]
        })
    }

	// 哈希表设值
	hash.set(obj,cloneObj);

	//Reflect.ownKeys(obj)拷贝不可枚举属性和符号类型
	for(let key of Reflect.ownKeys(obj)){
		// 如果值是引用类型并且非函数则递归调用deepClone
		cloneObj[key] = 
			(isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key],hash) : obj[key];
	}
	return cloneObj;
}

let obj = {
	arr : [0,1,2,3,4,5,6]
}

let obj2 = deepClone(obj);
obj2.str = 'flten'
console.log(obj,obj2);//{arr: [0, 1, 2, 3, 4, 5, 6],str: "flten"}

console.log('----------------------------------------------------------');

//对象循环引用测试
let a = {
    name: "lk",
    course: {
        vue: "Vue.js",
        react: "React.js"
    },
    a1: undefined,
    a2: null,
    a3: 123,
    a4: NaN
}

//对象循环引用
a.circleRef = a;

let b = deepClone(a);
console.log(b);
// {
// 	name: "lk",
// 	a1: undefined,
//	        a2: null,
// 	a3: 123,
//	        a4: NaN,
// 	course: {vue: "Vue.js",react: "React.js"},
// 	circleRef: {name: "lk",a1: undefined, a2: null, a3: 123, a4:NaN …}
// }
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值