JavaScript中的深拷贝和浅拷贝常用方法总结

本文探讨了JavaScript中引用类型值的深拷贝和浅拷贝,特别是浅拷贝的扩展运算符在处理深层嵌套结构时的问题。文章提到了lodash的cloneDeep、ramda的clone和rfdc等深拷贝方法,适用于处理多层对象和数组的拷贝需求。
摘要由CSDN通过智能技术生成

本文乃学习总结,学习参考自:https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089

对于引用类型(数值类型的拷贝就是字面的拷贝,就不说了)来说,赋值运算符 "=" 进行的拷贝是对引用的拷贝(实质上用的是同一个引用),其中一个值的改变,会导致另一个值随之改变。但有时我们并不想这样做,这就可以通过如下深拷贝和浅拷贝(两者复制的都是不同的引用)实现。以下介绍几种浅拷贝和深拷贝常用的几种方法。

let array = [1,2,3]; 
let copyArray = array; 
console.log(...array) // 1 2 3 
array[0] = 99; 
console.log(...array) // 99 2 3 
console.log(...copyArray) // 99 2 3

1. 浅拷贝

浅拷贝只适用没有嵌套的数组或对象,对于嵌套的数组或对象,浅拷贝将会失效。

// 1. 扩展运算符 ... 适合没有嵌套的数组和对象进行浅拷贝
const array = ['A','B','c']
const copyWithSpread = [...array] // 改变array 不会改变 copyWithSpread

// 2. Array.slice(start,length)方法,适合数组的浅拷贝
const copyWithSlice = array.slice() // 改变 array 不会改变 copyWithSlice

// 3. Object.assign() 可用于任何对象or数组的浅拷贝
const copyWithAssign = [] // Changes to array will not change copyWithAssign
Object.assign(copyWithAssign, array) // Object.assign(target, source)

// 4. Array.from() ,适用于数组的浅拷贝
const copyWithFrom = array.from()

1.1 扩展运算符的深层嵌套问题

如果对象或数组包含其他对象或数组,则浅拷贝将无法正常工作,因为嵌套对象实际上并未克隆。

// 当包含数组的JavaScript对象深度嵌套时,
// 扩展运算符仅复制的第一层的引用,但更深的值仍链接在一起。所以会造成深拷贝无效。
const nestedArray = [[1,2],['a','b'],[3]];
const nestedCopyWithSpread = [...nestedArray];
console.log(nestedCopyWithSpread); // [[1,2],['a','b'],[3]]

nestedArray[0][0] = 'hello';
console.log(nestedArray); // [["hello",2],['a','b'],[3]]
console.log(nestedCopyWithSpread); // [["hello",2],['a','b'],[3]]

1.2 深拷贝

适用嵌套多层对象和数组的对象or 数组

lodash: Lodash Documentation

radma: Ramda Documentation

rfdc: rfdc - npm

// 1. lodash库,深拷贝常用方法,简单易用
import _ from "lodash"
const nestedArray = [[1,2],['a','b'],[3]];
const shallowCopyWithLodashClone = _.clone(nestedArray) 
console.log(nestedArray[0] === shallowCopyWithLodashClone[0]) // true -- 浅拷贝(相同引用)

const deepCopyWithLodashCloneDeep = _.cloneDeep(nestedArray)
console.log(nestedArray[0] === deepCopyWithLodashCloneDeep[0]) // false -- 深拷贝 (不同引用)
nestedArray[0][0] = 'hello';
console.log(...nestedArray) // [["hello",2],['a','b'],[3]]
console.log(...shallowCopyWithLodashClone) // [["hello",2],['a','b'],[3]]
console.log(...deepCopyWithLodashCloneDeep) // [[1,2],['a','b'],[3]]

// 2. ramda库 
import R from "ramda" ;
const deepCopyWithRamdaClone = R.clone(nestedArray)
console.log(nestedArray[0] === deepCopyWithRamdaClone[0]) // false -- 深拷贝(不同引用)

/**
 * 3. JSON.parse(JSON.stringify(object)) 通常不被推荐,只适合一些特殊情况
 * 对象中不包含Dates, functions, undefined, Infinity, [NaN], 
 * RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types
 */
const referenceObject = {
  string: 'string',
  number: 123, boolean: false,
  null: null,
  notANumber: NaN, // NaN values will be lost (the value will be forced to 'null')
  date: new Date('1999-12-31T23:59:59'),  // Date will get stringified
  undefined: undefined,  // Undefined values will be completely lost, including the key             
  infinity: Infinity,  // Infinity will be lost (the value will be forced to 'null')
  regExp: /.*/, // RegExp will be lost (the value will be forced to an empty object {})
}
const jsonClone = JSON.parse(JSON.stringify(sampleObject))
console.log(jsonClone) // { string: "string", number: 123, boolean: false, null: null, notANumber: null, date: "2000-01-01T04:59:59.000Z", infinity: null, regExp: {} }

// 4. rfdc(Really Fast Deep Clone) ,非常高效的深度拷贝,速度比lodash的高400%
const clone = require('rfdc')() // Returns the deep copy function
const rfdcClone = clone(array);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值