本文乃学习总结,学习参考自: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);