(一)原码
<script>
//创建一个对象
var person = {
name : 'bart',
age :21,
friend :[{name : '张三',age : 23},{name : '李四',age : 21},{name : '王五',age : 22}],
hoddy : ['swimming','playing football','fishing running','listening'],
family : {
number : '1xxxxxxxxxx2',
address : '中国'
}
}
//利用递归函数,实现拷贝
function deepCopy(copyObj){
// 创建一个变量,先不确定变量类型,值为undefined
var obj
//判断copyObj是否是一个数组类型
if(Array.isArray(copyObj)){
//如果符合条件则给 obj一个空数组
obj = []
//通过数组的遍历进行拷贝
//由于数组的元素可以是任意数据类型,所以需要对内部在进行判断其数据类型
//这样也就有了obj[i] = deepCopy(copyObj[i]),通过此语句回调函数,完成判断
//直到对象遍历完,return obj直接退出deepCopy()函数
for(var i = 0 ; i < copyObj.length ; i++){
//通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
obj[i] = deepCopy(copyObj[i])
}
//循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
return obj
//array和对象类型的typeof()值都是object,由于上面if已经判断了array
//这里是用来判断copyObj是否是对象
}else if(typeof copyObj === 'object'){
//给obj一个空对象
obj = {}
//通过对象的遍历进行拷贝
//由于对象的属性可以是任意数据类型,所以需要对内部在进行判断其数据类型
//这样也就有了obj[key] = deepCopy(copyObj[key]),通过此语句回调函数,完成判断
//直到对象遍历完,return obj直接退出deepCopy()函数
for(var key in copyObj){
//通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
obj[key] = deepCopy(copyObj[key])
}
//循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
return obj
}else{
//没有上面两种类型的数据,就可以返回到调用它的地方
//如:obj[i] = deepCopy(copyObj[i])
//obj[key] = deepCopy(copyObj[key])
//当返回这个数据的时候说明这个属性到底了
return copyObj
}
}
//将要拷贝的对象作为实际参数,然后将返回值给var xin
var xin = deepCopy(person)
//遍历新的对象
for(var key in xin){
console.log(xin[key])
}
//对二者进行验证,如果实现深拷贝,则二者地址不同,改变一个的数据,另一个不会发生变化
xin.age = 22
console.log(xin.age)
console.log(person.age)
</script>(二)、解决思路
对对象的深拷贝的难点在于对象的属性值可以是任意类型,而数组的元素可以是任意属性,这样也恰恰是解决它的办法。
将每一数据都进行判断,判断的结果分为数组、对象、其他,对数组和对象进行再一次判断。为了方便也就有了递归函数,通过反复回调进行判断,直到既不会数组又不是对象的时候才会拷贝,最后通过return将拷贝成功的对象返回。
(三)、核心代码
function deepCopy(copyObj){
// 创建一个变量,先不确定变量类型,值为undefined
var obj
//判断copyObj是否是一个数组类型
if(Array.isArray(copyObj)){
//如果符合条件则给 obj一个空数组
obj = []
//通过数组的遍历进行拷贝
//由于数组的元素可以是任意数据类型,所以需要对内部在进行判断其数据类型
//这样也就有了obj[i] = deepCopy(copyObj[i]),通过此语句回调函数,完成判断
//直到对象遍历完,return obj直接退出deepCopy()函数
for(var i = 0 ; i < copyObj.length ; i++){
//通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
obj[i] = deepCopy(copyObj[i])
}
//循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
return obj
//array和对象类型的typeof()值都是object,由于上面if已经判断了array
//这里是用来判断copyObj是否是对象
}else if(typeof copyObj === 'object'){
//给obj一个空对象
obj = {}
//通过对象的遍历进行拷贝
//由于对象的属性可以是任意数据类型,所以需要对内部在进行判断其数据类型
//这样也就有了obj[key] = deepCopy(copyObj[key]),通过此语句回调函数,完成判断
//直到对象遍历完,return obj直接退出deepCopy()函数
for(var key in copyObj){
//通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
obj[key] = deepCopy(copyObj[key])
}
//循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
return obj
}else{
//没有上面两种类型的数据,就可以返回到调用它的地方
//如:obj[i] = deepCopy(copyObj[i])
//obj[key] = deepCopy(copyObj[key])
//当返回这个数据的时候说明这个属性到底了
return copyObj
}
}创建一个函数,在函数中写入判断条件,这样就可以通过调用函数反复判断,通过if-else语句判断属性数据类型,通过deepCopy(copyObj[key])以及deepCopy(copyObject[i])语句完成属性的判断,直到运行return copyObj才能完成一个拷贝动作,也就是拷贝到了一个值,当完成遍历之后所有的数据都拷贝完毕了,return obj返回拷贝数据。
(四)是判断数组在前还是判断对象在前问题
造成这个问题的主要原因在于数组类型和对象的typeof()都是object,由于Array.isArray()可以判断是否是数组,这样一来就一定是判断数组在前,判断对象在后,如果判断对象在前,则后面的判断数组会直接被覆盖掉,即使原对象中的属性存在数组也会以object输出,这个可以在f12开发者工具中查看。判断对象在前,数组在后,结果如图

版权声明:本文为weixin_53867427原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。