JavaScript中数据类型分为:基本类型、引用类型
-
基本类型
- Number、String、Boolean、Symbol、BigInt、Null、Undefined
- 保存在栈内存中,数据大小确定,按值存放。
- 赋值是在栈内存中开辟一段新的内存,将数据的值保存在这段内存中。
- 基本数据类型值不可变。
-
引用类型
- Object
- 值保存在堆内存中,指针保存在栈内存中。
- 赋值是将对象的指针指向到这个变量。
- 引用数据类型值可变
深拷贝和浅拷贝
let o = {
a: 12,
b: {
b1: 13
}
};
// 赋值操作符实现的是对象的浅拷贝
let oo = o;
// 使用JSON.parse(JSON.stringify())可以实现对象的深拷贝,但是缺点很大
let ooo = JSON.parse(JSON.stringify(o));
// 浅拷贝是将变量 o 保存的指针赋值给对象 oo
// 深拷贝是将变量 o 保存的指针对应的对象拷贝到另一块内存中,然后将新内存中的对象对应的指针赋值给 ooo
// 浅拷贝目标对象(oo)和原对象(o)指向的是同一块内存的对象,所以改变其中一个的值都会影响另一个变量的值
// 深拷贝针对的是不同内存中的对象,两者不会互相干扰
对象的深拷贝
// 原对象
let originObj = {
num: 12,
str: 'abc',
bool: false,
map: new Map([[0,'a'], [1, 'b']]),
set: new Set([1,2,3,4,5]),
func: function () {
console.log('func');
},
sym: Symbol('sym'),
date: new Date(),
n: null,
un: undefined,
obj: {
a: 100,
b: 'ddd'
},
el: document.createElement('span')
};
- 使用 JSON.parse(JSON.stringify(obj))
// 不存在递归引用
let obj = JSON.parse(JSON.stringify(originObj));
console.log(obj);
// 结果
{
num: 12,
str: "abc",
bool: false,
map: {},
set: {},
date: "2019-11-14T02:32:37.130Z",
n: null,
obj: {
a: 100,
b: "ddd"
},
el: {}
}
缺点:
* 若对象中存在值为Symbol、Undefined、Function等类型会丢失
* 对于Date等类型会执行toString方法
* 对于Map、Set、Element等类型会转为{}
- 自定义方法实现对象深拷贝
function deepClone(obj) {
const type = Object.prototype.toString.call(obj);
let newObj;
switch (type) {
case '[object Array]':
newObj = [];
for (let i = 0; i < obj.length; i++) {
newObj.push(deepClone(obj[i]));
}
break;
case '[object Object]':
const keys = Object.keys(obj);
newObj = {};
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
newObj[key] = deepClone(obj[key]);
}
break;
default:
newObj = obj;
break;
}
return newObj;
}
缺点:
- 对于有无限递归引用的对象:Uncaught RangeError: Maximum call stack size exceeded
- 耗时长,需要优化