更多个人博客:(https://github.com/zenglinan/blog)
如果对你有帮助,欢迎star。
对象拷贝是经常会遇到的场景, 本文会总结几种深浅拷贝的方法
一. 浅拷贝
1. 浅拷贝的定义
先来说说什么是浅拷贝, 首先要明确一点:
直接拷贝对象的引用这不叫浅拷贝
先来看一个案例:
拷贝引用:
var obj1 = {
a: 1,
b: {
c: 1
}
}
var obj2 = obj1 // 拷贝 obj1 的引用
obj2.a = 2
console.log(obj1.a) // 2
浅拷贝:
var obj1 = {
a: 1,
b: {
c: 1
}
}
var obj2 = {...obj1}
obj2.a = 2
console.log(obj1.a) // 1
上面可以看到, 直接复制引用时, 两个对象实际保存的是堆中同一个对象的引用, 而浅拷贝则不同, 浅拷贝重新生成了一个新的对象, 但是浅拷贝只会拷贝一层, 假如原对象的属性值为对象, 也只会拷贝这个对象的引用。
也就是说: 在浅拷贝的对象中, 修改基本类型的值不会影响原数据, 修改复杂类型时, 会影响原数据
2. 浅拷贝的实现
(1) ...扩展运算符
var copy = {...obj}
ES6 中提供了扩展运算符, 可以遍历取出对象身上的属性, 分配到新的对象上
(2) Object.assign
var copy = {}
Object.assign(copy, obj)
Object.assign 可以将第二个对象里可枚举的属性复制到第一个对象里
(3) for...in
function shallowCopy(src){
let result = {}
for(let prop in src){
if(src.hasOwnProperty(prop)){
result[prop] = src[prop]
}
}
return result
}
注意: for...in 循环会遍历原型链上所有的的属性, 浅拷贝只需拷贝对象身上的属性。
所以加一层 hasOwnProperty
判断
二. 深拷贝
1. 深拷贝的定义
与浅拷贝相比, 深拷贝也会对对象的子对象进行拷贝
当修改拷贝对象上的对象属性时, 不会对源对象产生影响
2. 深拷贝的实现
(1) JSON序列化与反序列化
最先说的办法当然是家喻户晓的 JSON 序列化与反序列化方法啦~
var copy = JSON.parse(JSON.stringify(src))
先序列化一下对象变成字符串, 然后再反序列化成对象
这个办法有两个缺陷:
-
既然是 JSON 对象上的方法, 当然不支持拷贝函数了o(╥﹏╥)o
-
同样的道理, JSON 里面没有 Symbol 类型, 自然也不支持 Symbol 类型的键
但是这个方法最简单了, 一行代码...
(2) for...in + 递归
function deepClone(src){
if(typeof src !== "object") return src
let result = Array.isArray(src) ? [] : {}
for(let prop in src){
if(!src.hasOwnProperty(prop)) continue
let value = src[prop]
result[prop] = typeof value === 'object' ? deepClone(value) : value
}
return result
}
这个方法比 JSON 序列化的方法更完善的一点是: 支持拷贝函数
但是依然无法拷贝键为 Symbol 类型的属性
原因是: for...in 无法遍历到 Symbol 类型的属性
(3) Reflect.ownKeys() + 递归
MDN 上是这样描述的:
Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组。它的返回值等同于
Object.getOwnPropertyNames(target)
.concat(Object.getOwnPropertySymbols(target))
这个方法可以取到对象自身的所有属性, 包括 Symbol 类型的属性
function deepClone(src){
if(typeof src !== 'object') return src
let result = Array.isArray(src) ? [] : {}
Reflect.ownKeys(src).forEach((key) => {
let value = src[key]
result[key] = typeof value === 'object' ? deepClone(value) : value
})
return result
}
网友评论