1. 数据存储类型
javaSript 中存在两种数据类型
- 基本类型
- 引用类型
基本类型保存在栈内存
引用类型的数据保存在堆内存中,引用类型的变量是一个指向堆内存中实际对象的引用地址,存在栈中
2. 浅拷贝
浅拷贝是指创建新的数据,这个数据有着原始数据属性值的一份精准拷贝
如果属性是基本类型,拷贝的是基本类型的值;如果属性是引用类型,拷贝的是内存地址;
浅拷贝
function shallowCoapy(obj) {
const newObj = {};
for (const k in obj) {
if (Object.hasOwnProperty.call(obj, k)) {
newObj[k] = obj[k];
}
}
return newObj;
}
其他浅拷贝方法
- Object.assgin
- 扩展运算符
Object.assgin
const objA = {
age: 18,
}
const objB = Object.assign({}, objA);
扩展运算符
const objA = {
age: 18
}
const objB = {
...objA
}
3. 深拷贝
深拷贝创建一个新的栈,递归复制对象的所有层,使得拷贝和原始对象没有引用类型的共享
常见的深拷贝方式
- lodash.cloneDeep()
- jQuery.extend()
- JSON.stringfy()
- 手写递归循环
lodash.cloneDeep()
import { cloneDeep } from 'lodash';
const objA = {
age: 18,
score: {
math: 90,
music: 80
},
};
const objB = cloneDeep(objA);
jQuery.extend()
import $ from 'jQuery';
const objA = {
age: 18,
score: {
math: 90,
music: 80
},
};
const objB = $.extend(objA);
JSON.stringfy()
const objA = {
age: 18,
score: {
math: 90,
music: 80
},
};
const objB = JSON.parse(JSON.stringify(objA));
缺点:会忽略一些特殊对象(Map、Set、Date、RegExp)
手写递归
function deepClone(obj, hash = new WeakMap()) {
// 如果是 null 或者不是对象和数组,直接返回
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 如果是日期类型,使用新的日期对象
if (obj instanceof Date) {
return new Date(obj);
}
// 如果是正则表达式对象,使用新的正则表达式对象
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// 如果循环引用了就用 weakMap 来解决
if (hash.has(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;
}
// 使用示例
const original = {
number: 1,
bool: false,
string: 'string',
date: new Date(),
undefined: undefined,
null: null,
array: [0, 1, 2],
object: {
child: { num: 1 }
},
regexp: new RegExp(/regexp/i)
};
const copied = deepClone(original);
console.log(copied);
总结
-
浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个内存地址
-
深拷贝是通过递归将所有层次进行拷贝,最终属性为对象的会指向不同的地址