JS深拷贝与浅拷贝
JS的数据类型
概念
JS是一种动态语言,也就是不需要提前声明变量的类型,在程序运行过程中,类型就会被自动确定,而且变量的数据类型是可以变化的。
基本数据类型和引用数据类型对比
基本数据类型 | 引用数据类型 | |
---|---|---|
数据类型 | String 、Number 、Boolean 、Null 、Undefined | Object (内置对象Function、Array、Date、RegExp、Error 等) |
最大的区别 | 参数赋值的时候传数值 | 参数赋值的时候,传地址(修改同一片内存空间) |
内存使用 | 基本数据类型的值,直接保存在栈内存中。值与值之间是独立存在,修改一个变量不会影响其他的变量。 | 对象是保存到堆内存中的。每创建一个新的对象,就会在堆内存中开辟出一个新的空间;而变量保存了对象的内存地址(对象的引用),保存在栈内存当中。如果两个变量保存了同一个对象的引用,当一个通过一个变量修改属性时,另一个也会受到影响。 |
深浅拷贝
概念
- 浅拷贝:只拷贝最外面一层的数据,对于更深层次的对象只拷贝它的引用(在栈内存中的引用,指向同一个堆内存),拷贝引用的时候是传址而不是传值
- 深拷贝:拷贝多层数据,使每一层级别的数据都会被拷贝
浅拷贝的实现
const obj1 = {
name:'obj1',
age:1,
skill: {
sing: 'many song'
}
};
const obj2 = Object.assign({},obj1);
obj2.skill.sing = 'no song';
console.log(obj1.skill.sing); //no song
深拷贝的实现
JSON.parse( JSON.Stringify() )实现深拷贝
//缺点:不可以拷贝undefined、function、RegExp等类型
const obj1 = {
name:'obj1',
age:1,
skill: {
sing: 'many song'
}
};
const obj2 = JSON.parse(JSON.stringify(obj1))
obj2.skill.sing = 'no song';
console.log(obj1.skill.sing); //many song
递归方式实现深拷贝
// 定义一个深拷贝函数 接收目标target参数
function deepClone(target) {
// 定义一个变量
let result;
// 如果当前需要深拷贝的是一个对象的话
if (typeof target === 'object') {
// 如果是一个数组的话
if (Array.isArray(target)) {
result = []; // 将result赋值为一个数组,并且执行遍历
for (let i in target) {
// 递归克隆数组中的每一项
result.push(deepClone(target[i]))
}
// 判断如果当前的值是null的话;直接赋值为null
} else if (target === null) {
result = null;
// 判断如果当前的值是一个RegExp对象的话,直接赋值
} else if (target.constructor === RegExp) {
result = target;
} else {
// 否则是普通对象,直接for in循环,递归赋值对象的所有值
result = {};
for (let i in target) {
result[i] = deepClone(target[i]);
}
}
// 如果不是对象的话,就是基本数据类型,那么直接赋值
} else {
result = target;
}
// 返回最终结果
return result;
}