搞定 JS 深浅拷贝

浅拷贝与深拷贝的区别

  • 浅拷贝是创建一个新的对象,如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址。如果这个内存地址的值发生了变化,就会影响到其他的对象。
  • 深拷贝是将一个对象从内存中完整拷贝一份出来,从内存中开辟一个新的区域放新对象,并且修改新对象不会影响原对象。

总而言之,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

禅 - 小鑫博客

禅

浅拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function shallowClone(source) {
let result = {}
for (let item in source) {
if (source.hasOwnProperty(item)) {
result[item] = source[item]
}
}
return result
}

let obj1 = {
name: '小鑫',
arr: [1, 2],
}

let obj2 = shallowClone(obj1)
obj2.name = '小小鑫'
obj2.arr[1] = [1, 2]

console.log('obj1', obj1)
// obj1 { name: '小鑫', arr: [ 1, [ 1, 2 ] ] }
console.log('obj2', obj2)
// obj2 { name: '小小鑫', arr: [ 1, [ 1, 2 ] ] }

对于基本类型,可以拷贝出来,但是引用类型拷贝的只是引用地址

深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function deepClone(obj) {
let result = new obj.constructor()
if (obj === null) return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// 普通类型不需要深拷贝
if (typeof obj !== 'object') return obj
for (let item in obj) {
if (obj.hasOwnProperty(item)) {
result[item] = deepClone(obj[item])
}
}
return result
}

let obj1 = {
name: '小鑫',
arr: [1, 2],
}

let obj2 = deepClone(obj1)
obj2.name = '小小鑫'
obj2.arr[1] = [1, 2]

console.log('obj1', obj1)
// obj1 { name: '小鑫', arr: [ 1, 2 ] }
console.log('obj2', obj2)
// obj2 { name: '小小鑫', arr: [ 1, [ 1, 2 ] ] }

一个基本的深拷贝就这样完成了,这里可以用 while 替代 for...in ,因为 whilefor...in 遍历的速度快,现在就来实现一个迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function forEach(array, iterate) {
let index = -1
const LEN = array.length
while (++index < LEN) {
iterate(array[index], index)
}
}

function deepClone(obj) {
let result = new obj.constructor()
if (obj === null) return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// 普通类型不需要深拷贝
if (typeof obj !== 'object') return obj
const keys = Object.keys(obj)
forEach(keys, (key, index) => {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key])
}
})
return result
}

let obj1 = {
name: '小鑫',
arr: [1, 2],
}

let obj2 = deepClone(obj1)
obj2.name = '小小鑫'
obj2.arr[1] = [1, 2]

console.log('obj1', obj1)
// obj1 { name: '小鑫', arr: [ 1, 2 ] }
console.log('obj2', obj2)
// obj2 { name: '小小鑫', arr: [ 1, [ 1, 2 ] ] }

niceeeeeeeeee~