直接赋值 (引用)、浅拷贝、深拷贝
区别
- 直接赋值 (引用): 其实就是对象的引用(别名)
- 浅拷贝: 拷贝父对象,不会拷贝对象的内部的子对象
- 深拷贝: 完全拷贝了父对象及其子对象
解析
- b = a: 赋值引用,a 和 b 都指向同一个对象
- b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)
- b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的
实现
浅拷贝
- 对象:Object.assign()
javascript
var obj = {a:{a:"kobe",b:39}}
var initalObj = Object.assign({},obj)
initalObj.a.a = "wade"
console.log(obj.a.a) //wade
这个 API 还可用于 对象合并
javascript
const ul = {name:"zhangsan"}
const u2 = {age: 12}
const u3 = Object.assign(ul,u2);
console.log(u3) // { name:'zhangsan',age: 12 }
object
只有一层的时候,是 深拷贝
- 数组:concat、slice
javascript
let arr1 = [ 1, 3, {
username:'kobe'
}]
let arr2 = arr1.slice() // 或者 let arr2 = arr.concat()
arr2[1] = 2
arr2[2].username = '6666'
console.log(arr1, arr2)
Array
的slice
和concat
方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组
深拷贝
扩展运算符
,也可以进行浅拷贝
- 序列化
JSON.parse(JSON.stringify())
- 缺点:虽然可以实现数组或对象深拷贝,但不能处理函数
- 递归遍历 手写实现
javascript
// 定义检测数据类型的功能函数
function checkedType(target){
return Object.prototype.toString.call(target).slice(8,-1)
}
// 实现深度克隆---对象/数组
function clone(target){
// 判断拷贝的数据类型
// 初始化变量result 成为最终克隆的数据
let result,targetType = checkedType(target)
if(targetType === 'Object'){
result = {}
}else if(targetType === 'Array'){
result = []
}else{
return target
}
// 遍历目标数据
for(let i in target){
// 获取遍历数据结构的每一项值
let value=target[i]
// 判断目标结构里的每一值是否存在对象/数组
if(checkedType(value) === 'Object' || checkedType(value) === 'Array'){ //对象/数组里嵌套了对象/数组
// 继续遍历获取到value值
result[i] = clone(value)
}else{ //获取到value值是基本的数据类型或者是函数
result[i] = value;
}
}
return result
}
原理:递归遍历所有对象、数组,直到都是基本数据类型,然后再去复制,就是深拷贝
- 第三方函数库
loadsh