先看一个例子:函数
// 对象类型在赋值的过程当中实际上是复制了地址,从而会致使改变了一方其余也都被改变的状况
let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2
复制代码
首先能够经过 Object.assign
来解决这个问题,不少人认为这个函数是用来深拷贝的。其实并非,Object.assign
只会拷贝全部的属性值到新的对象中,若是属性值是对象的话,拷贝的是地址,因此并非深拷贝。ui
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
复制代码
另外咱们还能够经过展开运算符 ...
来实现浅拷贝spa
let a = {
age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1
复制代码
一般浅拷贝就能解决大部分问题了,可是当咱们遇到以下状况就可能须要使用到深拷贝了code
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = { ...a }
a.jobs.first = 'native'
console.log(b.jobs.first) // native
复制代码
浅拷贝只解决了第一层的问题,若是接下去的值中还有对象的话,那么就又回到最开始的话题了,二者享有相同的地址。要解决这个问题,咱们就得使用深拷贝了。对象
这个问题一般能够经过 JSON.parse(JSON.stringify(object))
来解决。递归
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
复制代码
可是该方法有局限性:原型链
undefined
symbol
在遇到函数、 undefined
或者 symbol
的时候,该对象也不能正常的序列化原型
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}
复制代码
你会发如今上述状况中,该方法会忽略掉函数和 undefined
,可是在一般状况下,复杂数据都是能够序列化的,因此这个函数能够解决大部分问题。string
若是你所需拷贝的对象含有内置类型而且不包含函数,最好的方式是推荐[lodash 的深拷贝函数]
,由于实现一个深拷贝是很困难的,须要考虑好多种边界状况,好比原型链如何处理、DOM 如何处理等等it
在此实现一个简易版的深拷贝
// 递归拷贝
function deepClone(obj) {
let copy = obj instanceof Array ? [] : {}
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
}
return copy
}
复制代码