本文将手动实现引用类型的深拷贝
关于值类型与引用类型可阅读下方文章:
JS基础类型直通车:
Js基础知识-变量类型
Js基础知识-typeof运算符
let obj1={
name:'王',
age:23,
address:{
city:'河南省郑州市'
},
hobby:['play','eat']
}
let obj2=obj1
console.log(obj1.name) // 王
obj2.name='李'
console.log(obj1.name) // 李
由于直接将obj1直接赋值给了obj2,此时他们的指针地址是相同的,所以当obj2改变时,obj1的值也会改变。
如何将obj1赋值给obj2,修改obj2的值obj1得值不会改变?
- 创建方法deepClone,将返回一个值作为方法的返回值
/**
* 深度克隆
* @param {object} obj 需要克隆的对象/数组
*/
function deepClone(obj={}){
return obj
}
- 检查传入的参数类型是否为引用类型,不是的话将参数直接返回
/**
* 深度克隆
* @param {object} obj 需要克隆的对象/数组
*/
function deepClone(obj={}){
if(typeof obj!=='object'||obj==null){
return obj
}
}
- 处理参数为引用类型,检查是否为数组,定义新的变量
/**
* 深度克隆
* @param {object} obj 需要克隆的对象/数组
*/
function deepClone(obj={}){
if(typeof obj!=='object'||obj==null){
return obj
}
let result // 将要返回的变量
if(obj instanceof Array){
result=[] // 如果Obj为数组,则将返回定义为空数组
}else{
result={} // 如果Obj为对象,则将返回定义为空对象
}
}
- 遍历赋值
会用到递归,如果不清楚可以将每一个obj的值进行打印。
/**
* 深度克隆
* @param {object} obj 需要克隆的对象/数组
*/
function deepClone(obj={}){
if(typeof obj!=='object'||obj==null){
return obj
}
let result // 将要返回的变量
if(obj instanceof Array){
result=[] // 如果Obj为数组,则将返回定义为空数组
}else{
result={} // 如果Obj为对象,则将返回定义为空对象
}
// forin可以用于对象和数组的遍历
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result[key]=deepClone(obj[key]) // 使用递归
}
}
}
- 再次声明测试
/**
* 深度克隆
* @param {object} obj 需要克隆的对象/数组
*/
function deepClone(obj={}){
console.log(obj)
//obj每次的值
//王 23 {city: "河南省郑州市"} 河南省郑州市 ["play", "eat"] play eat
if(typeof obj!=='object'||obj==null){
return obj
}
let result // 将要返回的变量
if(obj instanceof Array){
result=[] // 如果Obj为数组,则将返回定义为空数组
}else{
result={} // 如果Obj为对象,则将返回定义为空对象
}
// forin可以用于对象和数组的遍历
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result[key]=deepClone(obj[key]) // 使用递归
}
}
return result
}
let obj2=deepClone(obj1)
obj2.name='李'
console.log(obj1.name,obj2.name) // 王 李
经过手动实现深度拷贝后就会发现,当改变obj2的值后,obj1并不会发生改变。
上一章 : Js基础知识-typeof运算符