一般来说,我们拷贝数据的时候:
如果是基本数据类型,则会生成新的数据,修改拷贝后的数据不会影响原有数据。
如果是对象/数组,并不会生成新的数据,而是拷贝引用,修改拷贝数据会影响原有数据。
常用的几种拷贝方法
- 直接赋值
let person = {
name: 'Jack'
}
let newPerson = person
newPerson.name = 'Tom'
console.log(person.name) // Tom 修改拷贝后的数据会影响原有数据,浅拷贝
Object.assign()
let person = {
name: 'Jack',
otherInfo: {
age: 22
}
}
let newPerson = {}
Object.assign(newPerson, person)
newPerson.otherInfo.age = 33
console.log(person.otherInfo.age) // 33 修改拷贝后的数据会影响原有数据,浅拷贝
Array.prototype.concat()
let arr = [1, 2, { name: 'Jack'}]
let newArr = arr.concat([])
newArr[2].name = 'Tom'
console.log(arr[2].name) // Tom 修改拷贝后的数据会影响原有数据,浅拷贝
Array.prototype.slice()
let arr = [1, 2, { name: 'Jack'}]
let newArr = arr.slice(0)
newArr[2].name = 'Tom'
console.log(arr[2].name) // Tom 修改拷贝后的数据会影响原有数据,浅拷贝
- 扩展运算符
...
let person = {
name: 'Jack',
otherInfo: {
age: 22
}
}
let newPerson = { ...person }
newPerson.otherInfo.age = 33
console.log(person.otherInfo.age) // 33 修改拷贝后的数据会影响原有数据,浅拷贝
JSON.parse(JSON.stringify())
let person = {
name: 'Jack',
otherInfo: {
age: 22
}
}
let newPerson = JSON.parse(JSON.stringify(person))
newPerson.otherInfo.age = 33
console.log(person.otherInfo.age) // 22 修改拷贝后的数据不会影响原有数据,深拷贝
可以看出,1~5均为浅拷贝,只有6是深拷贝。但是在遇到函数、undefined 或者symbol 的时候,JSON.parse(JSON.stringify())
并不能正常的序列化
// let person = undefined
// let person = Symbol('Jack')
let person = function() {
console.log('Jack')
}
console.log(JSON.parse(JSON.stringify(person))) // 报错 Uncaught SyntaxError: Unexpected token u in JSON at position 0
自定义深拷贝方法
利用递归,只要某个属性是对象类型,就递归;若是其他类型,则直接复制。代码如下:
function deepCopy(data) {
if (typeof data !== 'object' || data === null) { // typeof null 的结果是 object
return data
}
let result = Array.isArray(data) ? [] : {}
for (let key in data) {
// for...in 会遍历obj原型上的属性,因此需要用hasOwnProperty(key)来判断下当前属性是否属于obj
if (data.hasOwnProperty(key)) {
if (typeof data[key] === 'object') {
result[key] = deepCopy(data[key])
} else {
result[key] = data[key]
}
}
}
return result
}
lodash库的深拷贝方法
_.cloneDeep(value)
:该函数会递归拷贝value的属性,是深拷贝。
总的来说,对于一般的深拷贝,使用JSON.parse(JSON.stringify())
即可,如果遇到特殊的含有函数的对象,则可以自己封装一个深拷贝函数或者使用lodash库的cloneDeep(value)
函数。
网友评论