遇见一个问题,解决的时候衍生出了几条底层原理。为此做一下总结
let arr = ['1', '2', '3', {
name: 'zhangsan'
}, {
name: 'lisi'
}]
声明一个数组,要求对数组进行深拷贝
一 、 深拷贝和浅拷贝的区别
所有基础数据类型(String,Number,null,undefind,Boolean)进行赋值时都是深拷贝
所有声明的变量在赋值引用数据类型时,都是浅拷贝,因为引用数据类型都是存放在堆中,而声明的变量就相当于一个指针,指向了堆中的数据,所以在进行赋值的时相当于只复制了指针。当堆中的数据发生改变,指向数据的变量也会发生改变。
而深拷贝就相当于把存放在堆中的数据拿出来在存储一份。
常用实现深拷贝的方法有
转换成JSON字符串,再将其转换回来
let newarr = JSON.parse(JSON.stringfiy(arr))
递归的方法实现深拷贝
Object.prototype.copy = function (arr) {
if (typeof arr === 'object') {
let newarr = Object.prototype.toString.call(arr).slice(8,-1) == "Array" ? [] : {}
for(let key in arr){
newarr[key] = typeof(arr[key]) === 'object' ? copy(arr[key]) : arr[key]
}
return newarr
} else {
return arr
}
}
let arr2 = copy(arr)
arr[4].name = "王五"
console.log(arr,arr2);
创建一个copy( )方法放在Object的原型上
这里放张图片解释下原型之间的关系
进入递归后首先判断传递进来的数据的数据类型,判断数据类型的方法有
1、 typeof 判断基础数据类型,返回一个字符串。无法判断引用数据类型,因为万物皆对象,所以在使用typeof 判断数组的时候也会返回object
2、instanceof 可以用来判断引用数据类型
// 例如 判断arr 是否为数组
console.log(arr instanceof Array) // 返回true //返回boolean类型的值,true或者false
console.log(obj instanceof Array) //返回false
//但是当判断arr 是否为对象时,会返回true,因为数组也是特殊的对象
console.log(arr instanceof Object) //返回true
3、通过原型的construtor属性判断数据类型
理应constructor方法可以解决问题了,但是因为undefined和null没有constructor,所以是不能够判断出类型的,并且会报错
4、Object.prototype.toString.call() 完美解决问题
最后对递归实现深拷贝做下解释
Object.prototype.copy = function (arr) {
//判断传递进来的数据类型,如果不是数组或者对象,
if (typeof arr === 'object') {
//声明变量,如果arr是数组就 赋值 [],对象就赋值{}
let newarr = Object.prototype.toString.call(arr).slice(8,-1) == "Array" ? [] : {}
//循环arr
for(let key in arr){
// 将arr对应的key值,赋值给newarr时判断,如果key值也是对象或数组,再次调用函数递归
newarr[key] = typeof(arr[key]) === 'object' ? copy(arr[key]) : arr[key]
}
return newarr
} else { //直接 return
return arr
}
}
let arr2 = copy(arr)
arr[4].name = "王五"
console.log(arr,arr2);
以上