js的数据存储方式
- 基本数据类型:变量名(a)和变量值(1) 存储在栈中
- 复杂数据类型:变量名(b),存储在栈中;变量值({name: 'lihua'}),存储在堆中
赋值
首先说明这里说的赋值,不是直接把引用值(例如:{})或者原始值(例如:false、1、"str"等)直接赋值给一个变量。而是通过变量把一个值赋值给另一个变量。
深拷贝和浅拷贝
- 浅拷贝是什么?
浅拷贝是创建一个新对象,这个对象有原始对象属性值的一份精确拷贝。 如果属性是基本类型,拷贝的就是基本类型的值; 如果属性时引用类型,拷贝的就是内存地址。
let obj = {
name: 'll',
hobby: ['买花', '逛街'],
};
// 方法1: let obj1 = {...obj}
// 方法2: let obj1 = Object.assign({}, obj);
// 方法3:递归
function shallCopy(source) {
// 突出一个『新』对象
let obj = {};
for (let i in source) {
if (source.hasOwnProperty(i)) {
obj[i] = source[i];
}
}
return obj;
}
let obj1 = shallCopy(obj);
obj.name = 'emma';
// hobby是引用数据类型
obj.hobby[0] = '吃饭';
console.log(obj);
/**
* {
* name: "emma",
* hobby: ['吃饭', '逛街']
* }
*/
console.log(obj1);
/**
* {
* name: "ll",
* hobby: ['买花', '逛街']
* }
*/
// 注:直接修改 obj.hobby = {}, obj1的hobby不会变,相当于直接修改源,而不是引用类型
- 深拷贝是什么?
深拷贝拷贝是创建一个新对象,深拷贝是将一个对象从内存中完整的拷贝份出来,从堆内存中开辟一个新的区域存放新对象,彼此完全独立。 如果属性是基本类型,拷贝的就是基本类型的值; 如果属性是引用类型,贝的不是内存地址而是要从堆内存中开辟一个新的区域存放新对象, 彼此完全独立。
let obj = {
name: 'll',
hobby: ['买花', '逛街'],
// JSON拷贝,无法处理
date: new Date(),
};
// 方法1:
// 使用JSON.parse(JSON.stringify(xxx))
let deepObj = JSON.parse(JSON.stringify(obj))
// 注:没法对函数,日期,正则那些处理
obj.name = 'emma';
obj.hobby[0] = '吃饭';
console.log(obj);
/**
* {
* name: "emma",
* hobby: ['吃饭', '逛街']
* }
*/
console.log(deepObj);
/**
* {
* name: "ll",
* hobby: ['买花', '逛街']
* }
*/
// 方法2:
// 使用递归方法(https://juejin.cn/post/7075351322014253064)
function deepCopy(source) {
if (typeof source === null) {
return source;
}
if (source instanceof Date) {
return new Date(source);
}
if (source instanceof RegExp) {
return new RegExp(source);
}
// ... (类型)判断
if (typeof source !== 'object') {
return source;
}
let obj = Array.isArray(source) ? [] : {};
for (let i in source) {
if (source.hasOwnProperty(i)) {
obj[i] = deepCopy(source[i]);
}
}
return obj;
}
// 方法3: lodash中的cloneDeep
// 方法4:structuredClone(value),有兼容问题
注意:
-
赋值操作符是把一个对象的引用赋值给一个变量,所以变量中存储的是对象的引用。
-
浅复制是复制源对象的每个属性,但如果属性值是对象,那么复制的是这个对象的引用。所以源对象和拷贝对象之间共享嵌套对象。
-
深复制与浅复制不同的地方在于,如果属性值为对象,那么会复制该对象。源对象和拷贝对象之间不存在共享的内容。