JavaScript 中的深拷贝和浅拷贝
关于深拷贝和浅拷贝的定义:
- 浅拷贝 - 创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
- 深拷贝 - 将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
使用 JSON.parse(JSON.stringify()) 来实现深拷贝
可以使用 JSON.parse(JSON.stringify(obj)) 来实现对目标对象的深拷贝,但是这种方法有很多缺陷:
如果
undefined、Symbol和 函数是对象的属性值或以Symbo值为键的属性值,拷贝的对象会丢失这些属性1
2
3
4
5
6
7
8
9
10
11const originObj = {
name: 'Trump',
age: 94,
phone: undefined,
idNo: Symbol('1900'),
speak: () => console.log('I am Trump'),
[Symbol.for('weight')]: 120,
}
const copyObj = JSON.parse(JSON.stringify(originObj));
console.log(copyObj); // { name: 'Trump', age: 94 }无法处理循环引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const team = {
teamName: 'MAGA',
}
const originObj = {
name: 'Trump',
age: 94,
phone: undefined,
idNo: Symbol('1900'),
speak: () => console.log('I am Trump'),
[Symbol.for('weight')]: 120,
team,
}
team.leader = originObj;
const copyObj = JSON.parse(JSON.stringify(originObj));
console.log(copyObj); // TypeError: Converting circular structure to JSON
一个比较全面的深拷贝实现
1 | const TYPE_OBJECT = '[object Object]'; |
为什么使用 while 实现遍历
1 | const ARRAY_SIZE = 10000000; |
| 遍历方式 | for...in |
for |
forEach |
while |
|---|---|---|---|---|
| 100 | 0.103ms | 0.012ms | 0.027ms | 0.007ms |
| 10 | 0.088ms | 0.005ms | 0.022ms | 0.003ms |
| 1000 | 0.313ms | 0.036ms | 0.052ms | 0.028ms |
| 10000 | 1.332ms | 0.299ms | 0.316ms | 0.252ms |
| 100000 | 14.167ms | 1.691ms | 1.977ms | 1.428ms |
| 1000000 | 140.967ms | 2.928ms | 14.94ms | 3.012ms |
| 10000000 | 2.748s | 13.197ms | 141.273ms | 15.944ms |
| 20000000 | 7.824s | 22.389ms | 254.557ms | 28.07ms |
| 30000000 | 17.107s | 33.414ms | 375.766ms | 44.301ms |
综合来看,在百万量级的数据下,使用 while 进行遍历所耗费的时间最少。
判断引用类型
1 | const isObj = (value) => { |
获取数据类型
每一个引用类型都有toString方法,默认情况下,toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中type是对象的类型。
1 | const getType = (value) => { |