【前端进阶】数组和对象的深浅克隆

浅克隆

  1. 只克隆了第一级,对于后代级别还是公用之前的
  2. 操作新克隆的对象中的某些仍然可以改变原对象中的内容

1.循环遍历

对象

let obj = {
	name:'牧鱼',
	age:26,
	other:{
		job:'前端',
		city:'杭州'
	}
}

let clone ={},
	keys = [
	...Object.keys(obj),
	...Object.getOwnPropertySymbols(obj)
]

keys.forEach((item)=>{
	clone[item] = obj[item]
})

console.log(obj===clone) // false
console.log(obj.other===clone.other) // true

数组

let arr = [1,2,3,[4,5]]
let clone = []

// forEach
arr.forEach((item,index)=>{
	clone[index] = item
})

//或者 map
clone = arr.map(item => item)

console.log(arr===clone) // false
console.log(arr[3]===clone[3]) // true

2.展开运算符

对象

let obj = {
	name:'牧鱼',
	age:26,
	other:{
		job:'前端',
		city:'杭州'
	}
}

let clone ={...obj};

console.log(obj===clone) // false
console.log(obj.other===clone.other) // true

数组

let arr = [1,2,3,[4,5]]
let clone = [...arr]

console.log(arr===clone) // false
console.log(arr[3]===clone[3]) // true

3.Object.assign

对象

let obj = {
	name:'牧鱼',
	age:26,
	other:{
		job:'前端',
		city:'杭州'
	}
}

let clone = Object.assign({},obj);

console.log(obj===clone) // false
console.log(obj.other===clone.other) // true

数组

let arr = [1,2,3,[4,5]]
let clone = Object.assign([],arr)

console.log(arr===clone) // false
console.log(arr[3]===clone[3]) // true

4.slice/concat(数组)

let arr = [1,2,3,[4,5]]

// slice
let clone = arr.slice()

//或者 slice
let clone = arr.concat([])

console.log(arr===clone) // false
console.log(arr[3]===clone[3]) // true

深克隆

  1. 当前级及其所有后代级别,都会克隆一份一模一样的,和原始的数据结构不存在任何关联
  2. 消耗内存空间

1.JSON.parse(JSON.stringify(对象/数组))

  1. 基于JSON.stringify,把原始的对象/数组转换为字符串
  2. 再基于JSON.parse,把字符串转化为对象,此时对象中所有级别的堆内存都是全新开辟的
  3. JSON.stringify转化为字符串时,对很多类型不支持
  4. 不支持1:正则对象/Math对象会被处理为空对象
  5. 不支持2:值为函数/Symbol/undrfined的属性会被删除
  6. 不支持3:bigInt无法处理,报错:Uncaught TypeError: Do not know how to serialize a BigInt
  7. 不支持4:日期对象处理完成后,还是字符串
let obj = {
	name:'牧鱼',
	age:26,
	other:{
		job:'前端',
		city:'杭州'
	},
	reg:/^牧鱼$/g,
	math:Math,
	fn:function(){},
	sym:Symbol(1),
	un:undefined,
	big:10n,
	date:new Date()
}

let clone = JSON.parse(JSON.stringify(obj));

console.log(obj===clone) // false
console.log(obj.other===clone.other) // false
console.log(clone.reg) // {}
console.log(clone.math) // {}
console.log(clone.fn) // undefined
console.log(clone.sym) // undefined
console.log(clone.un) // undefined
console.log(clone.big) // Uncaught TypeError: Do not know how to serialize a BigInt
console.log(clone.date) // "2020-10-19T13:20:59.652Z"

自定义方法实现浅克隆与深克隆

// 获取对象或数组的私有属性,包含symbol
function getOwnProperty(obj){
	if(obj == null) return [];
	return [
		...Object.keys(obj),
		...Object.getOwnPropertySymbols(obj)
	]
}

// 浅克隆
function shallowClone(obj){
	let type = typeof obj;
	let toString = Object.prototype.toString;
	
	// 处理 null/undefined
	if (obj==null) return obj;
	
	// 处理 其余原始数据类型
	if(type!=="function"&&type!=="object") return obj;
	
	// 处理 方法
	if(type==="function"){
		return function proxy(){
			return obj()
		}
	}
	
	// 处理 日期对象和正则对象
	if(/(Date|RegExp)/.test(toString.call(obj))) return new obj.constructor(obj);
	
	// 处理 错误对象
	if(/Error/.test(toString.call(obj))) return new obj.constructor(obj.message);
	
	// 只处理数组(返回数组)和对象(普通对象,类数组对象返回普通对象)
	let keys = getOwnProperty(obj),
		clone ={};
	Array.isArray(obj) ? clone = [] : null;
	keys.forEach((key)=>{
		clone[key] = obj[key]
	})
	return clone
}

// 深克隆
function deepClone(obj,cache = new Set()){
	let toString = Object.prototype.toString;
	
	// 只对数组和对象再处理,其余情况直接按照浅克隆
	if(!/(Object|Array)/.test(toString.call(obj))) return shallowClone(obj);
	
	// 避免因自己套用自己导致的无限递归
	if(cache.has(obj)) return shallowClone(obj);
	cache.add(obj);
	
	let keys = getOwnProperty(obj),
		clone = {};
	/Array/.test(toString.call(obj))?clone = []:null;
	keys.forEach((key)=>{
		clone[key] = deepClone(obj[key],cache)
	})
	return clone
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值