JavaScript 中的浅拷贝与深拷贝
拷贝是指创建一个与原对象具有相同内容的数组或对象。根据拷贝的"深度",可以将其分为浅拷贝和深拷贝两种类型。
浅拷贝
浅拷贝是创建一个新对象或数组,只复制原始对象内容的第一层属性值(对于引用类型的属性,复制的是引用地址而非实际内容)
-
浅拷贝的特点
当复制一个对象的属性时,对于基本数据类型会复制其实际值。对于引用类型的属性,复制的是引用地址而非实际内容。只拷贝一层,不会递归拷贝嵌套对象
const original = { nested: { a: 1 } }; const copy = { ...original }; // 比较嵌套对象的引用 console.log(copy.nested === original.nested); // true // 证明它们引用的是同一个嵌套对象**外层对象:**由于
const copy = { ...original }创建的是全新的外层对象,所以original与copy是两个完全独立的对象,它们的内存地址不相同。console.log(original === copy) // false内层引用类型属性:对于对象内部的引用类型属性(如
obj.a是对象/数组),浅拷贝复制的是这个属性的引用地址(指针),新旧两个外层对象共享同一个嵌套对象,所以会有:console.log(copy.nested === original.nested); // true -
实现浅拷贝的常用方法
拷贝对象
浅拷贝拷贝对象有两种方式,拓展运算符(...)和
Object.assign()const original = { a: 1, b: { c: 2 } }; const copy = { ...original }; copy.a = 10; // 修改基本类型属性 copy.b.c = 20; // 修改嵌套对象(会影响原对象) console.log(original); // { a: 1, b: { c: 20 } }Object.assign()const original = { a: 1, b: { c: 2 } }; const copy = Object.assign({}, original); copy.a = 10; copy.b.c = 20; console.log(original); // { a: 1, b: { c: 20 } }拷贝数组
拷贝数组可以通过 (...)、
Array.slice()、Array.from()const original = [1, 2, { a: 3 }]; const copy = original.slice(); // const copy1 = Array.from(original); const copy2 = [...original] const copy3 = [].concat(original); console.log(copy); // [1, 2, { a: 30 }] console.log(copy1); // [1, 2, { a: 30 }] console.log(copy2); //[1, 2, { a: 30 }] console.log(copy3); //[1, 2, { a: 30 }] console.log(original); // [1, 2, { a: 30 }] -
浅拷贝的应用场景
确定对象没有嵌套引用需要独立拷贝时、性能要求高且能接受共享引用的场景、只需要第一层属性独立的简单情况
如:快速创建对象副本(当不需要深度拷贝时)函数参数传递(避免直接修改输入参数)React/Vue 状态更新(触发响应式更新)
深拷贝
深拷贝会递归复制对象或数组的所有层级,创建一个完全独立的新对象,新旧对象之间不会共享任何引用。
-
实现方式
JSON.parse(JSON.stringify()),使用这种无法处理函数、undefined、symbol、循环引用等const original = { a: 1, b: { c: 2 } }; const copy = JSON.parse(JSON.stringify(original)); console.log(copy) //{ a: 1, b: { c: 2 } }**
Lodash的cloneDeep**方法const _ = require('lodash'); const original = { a: 1, b: { c: 2 } }; const deepCopy = _.cloneDeep(original); -
运用场景
当对象结构复杂,有多层嵌套,或者需要完全独立的新对象,不希望新旧对象有任何关联