✨为什么会有两种拷贝方式
JavaScript中有两种不同的数据类型,分别是值类型(基本类型)
和引用数据类型(对象类型)
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
⌛ Js的基本类型
都存在栈内存中,这是因为基本类型
的值大小固定,所以它们可以直接存储在变量所在的栈上。每当创建一个变量时,就会在栈内存中为该变量分配内存空间。当变量不再被需要时,这段内存空间也会被释放,以便其他变量可以使用它。
⌛ 相对的Js的引用类型
的值存在堆内存中,而栈内存中只存储了该值的引用或指针。这是因为它们的大小是可变的,需要动态地在堆内存中为它们分配和回收空间。无法直接存储在变量所在的栈上。
⌛所以引用类型
进行拷贝时,会出现两种情况: 深拷贝和浅拷贝,而深拷贝和浅拷贝主要区别在于拷贝后的对象与原对象是否是同一对象(即是否是引用相同)
✨浅拷贝:
- 浅拷贝只是复制对象的引用,而不是对象本身。这意味着新变量只是源变量的一个副本,但是它们指向同一个对象内存地址。因此,改变新变量中的值将会影响到源变量,反之亦然。
- 浅拷贝的实现方式有 Object.assign() 和展开运算符(…),直接=号赋值
✨深拷贝:
- 深拷贝可以将对象及其嵌套对象的所有值都复制到一个新的对象里面,所以新对象和源对象互不影响。也就是在堆内存中开辟新的内存空间
- 深拷贝的实现方式
- JSON.parse(JSON.stringify(obj)) 进行深度复制 (不能处理 undefined、函数和循环引用等特殊情况)
- 使用递归函数实现深拷贝(要考虑性能问题)
/** * 深拷贝 * @param {object}} * @returns {object} * **/ function deepClone(obj) { // 首先判断要复制的是对象还是数组 let clone = Array.isArray(obj) ? [] : {}; // 遍历 obj,将其属性赋值到 clone 对象中 for (let key in obj) { if (obj.hasOwnProperty(key)) { // 如果属性是一个对象,则递归调用 if (typeof obj[key] === 'object' && obj[key] !== null) { clone[key] = deepClone(obj[key]); } else { clone[key] = obj[key]; } } } return clone; }