🍎 JavaScript 深拷贝与浅拷贝
回顾 JavaScript 中两大类数据类型:基本数据类型与引用数据类型。
- 基本类型数据保存在 栈内存;
- 引用类型数据保存在 堆内存。引用数据变量是一个指向堆内存中保存在栈内存中实际对象的引用。
# 概念
浅拷贝:指的是创建新的数据,这个数据有着原始数据的属性值的一份精确拷贝。
如果属性是 基本类型,拷贝的值就是基本类型的值;
如果属性是 引用类型,拷贝的值是 内存地址;
简单地说,浅拷贝就是一层的拷贝,对于深层次引用类型仅共享内存地址。
- 在
JavaScript
中,存在浅拷贝的现象有:Object.assign
Array.prototype.slice()
,Array.prototype.concat()
- 使用拓展运算符实现的复制
- 在
🌰 例子 / Object.assign
:
let obj = {
age: 18,
name: 'simon'
}
let newObj = Object.assign({}, obj)
console.log(newObj)
1
2
3
4
5
6
7
2
3
4
5
6
7
🌰 例子 / Array.prototype.slice()
:
const arr = ['a', 'b', 'c']
const newArr = arr.slice(0)
newArr[0] = 'd'
console.log(arr) // ["a", "b", "c"]
console.log(newArr) // ["d", "b", "c"]
1
2
3
4
5
6
2
3
4
5
6
同理,拓展运算符:
const arr = ['a', 'b', 'c']
const newArr = [...arr]
newArr[0] = 'd'
console.log(arr) // ["a", "b", "c"]
console.log(newArr) // ["d", "b", "c"]
1
2
3
4
5
6
7
2
3
4
5
6
7
深拷贝:开辟一个新的栈,两个对象属性完全相同,但是对应两个不同的内存地址。所以修改其中一个对象的属性,不会改变另一个对象的属性。
常见的深拷贝方式有:
_.cloneDeep()
jQuery.extend()
JSON.stringify()
- 手写循环递归
🌰 例子 / _.cloneDeep()
:
const _ = require('lodash');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1)
console.log(obj1.b.f === obj2.b.f) // false
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🌰 例子 / 循环递归实现深拷贝:
function deepClone(obj, hash = new WeakMap()) {
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;
// 如果是对象则深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- 浅拷贝与深拷贝的区别:
- 浅拷贝复制对象时,只复制指向某个对象的指针,而不复制对象本身,新旧对象是共享同一块内存,修改复制后的对象属性会影响原对象。
- 深拷贝会另外创造一个与原对象一样的对象(新开栈),新对象与原对象不共享内存,修改新对象不会影响原对象。
# 相关实现例子
🌰 例子 / 简单实现浅拷贝:
点击查看
function shallowClone(obj) {
const newObj = {}
for (let prop in obj) {
if (obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop]
}
}
return newObj
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 参考
编辑 (opens new window)
📢 上次更新: 2022/09/02, 10:18:16