interview
javascript-frontend-basics
Object.assign 和对象扩展运算符有什么区别是深拷贝还是浅拷贝

前端 JavaScript 基础面试题, Object.assign 和对象扩展运算符有什么区别?是深拷贝还是浅拷贝?

前端 JavaScript 基础面试题, Object.assign 和对象扩展运算符有什么区别?是深拷贝还是浅拷贝?

QA

Step 1

Q:: Object.assign 和对象扩展运算符有什么区别?是深拷贝还是浅拷贝?

A:: Object.assign 和对象扩展运算符 (...) 都用于对象的合并,但它们都是浅拷贝。Object.assign 会将一个或多个源对象的所有可枚举属性复制到目标对象。对象扩展运算符则是将一个对象的所有可枚举属性拷贝到新对象中。由于这两种方法都只对第一层属性进行拷贝,如果源对象中有嵌套对象,那么这些嵌套对象的引用会被拷贝,而不是嵌套对象的值。因此它们都只能进行浅拷贝。

Step 2

Q:: 什么是深拷贝,什么是浅拷贝?

A:: 浅拷贝是指创建一个新对象,这个对象有着原始对象属性值的精确副本。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是引用地址。因此,如果一个对象通过浅拷贝进行复制,当一个对象的属性值改变时,另一个对象的相应属性值也会改变。深拷贝是指将一个对象从内存中完整的拷贝出来,在堆内存中重新分配一块内存给新对象,且修改新对象不会影响旧对象。通常可以使用 JSON.parse(JSON.stringify(obj)) 来实现深拷贝,但这种方法有其局限性,比如无法拷贝函数、undefined、循环引用等。

Step 3

Q:: 如何实现一个深拷贝?

A:: 实现深拷贝的方法有很多,最简单的方式是使用 JSON.parse(JSON.stringify(obj))。然而这种方法不能处理函数、undefined、循环引用等情况。为了更完善地实现深拷贝,可以使用递归来复制每一层对象的属性。第三方库如 lodash 的 _.cloneDeep 也提供了方便的深拷贝功能。

用途

面试这个内容是为了考察候选人对 JavaScript 中对象操作的理解,特别是对拷贝机制的掌握。在实际生产环境中,对象的深拷贝和浅拷贝非常常见,尤其是在处理复杂状态管理时,比如在 React 或 Vue 等前端框架中,当需要拷贝组件状态时,需要清楚了解何时应该使用深拷贝或浅拷贝,以避免意外的引用问题导致数据篡改。\n

相关问题

🦆
什么是可枚举属性?

可枚举属性是指那些内部特性 [[Enumerable]] 被设置为 true 的属性。这些属性会在 for...in 循环和 Object.keys() 中被枚举出来。大多数通过普通语法创建的对象属性默认是可枚举的,但有些内置方法或通过 Object.defineProperty 创建的属性默认是不可枚举的。

🦆
对象的拷贝方式还有哪些?

除了 Object.assign 和对象扩展运算符之外,其他的拷贝方式还有手动遍历属性进行赋值、使用第三方库(如 lodash 的 _.cloneDeep)、使用结构化克隆算法(如 structuredClone)等。每种方式都有其优缺点,选择适合的拷贝方法需要根据具体的应用场景来决定。

🦆
如何处理循环引用的对象拷贝?

处理循环引用的对象拷贝需要在深拷贝过程中记录已经拷贝过的对象,避免无限递归。可以通过维护一个 WeakMap 来存储已经拷贝的对象,在遇到循环引用时直接返回该对象。

🦆
使用 JSON.parseJSON.stringifyobj 进行深拷贝有哪些局限性?

使用 JSON.parse(JSON.stringify(obj)) 进行深拷贝有几个局限性:无法拷贝函数、undefined、Symbol;无法处理循环引用;Date 对象会被转换为字符串;RegExp 对象会被转换为空对象;会丢失原型链。因此,这种方法适合用于简单的对象拷贝,而不适用于复杂对象。