const numbers = [1, [2], [3, [4]], 5];
// Using JavaScript
JSON.parse(JSON.stringify(numbers));
// Using Lodash
_.cloneDeep(objects);
复制代码
为了搞清楚为何有两种类型的拷贝,咱们来深度了解一下基础知识而后解释什么是引用类型。数组
与原始类型(number、string)不一样,数组是引用类型。这意味着当你把一个数组赋值给一个变量,你是将数组的内存地址而非数组自己赋给变量。 😱bash
这里没什么大不了的,咱们建立一个value
的拷贝。当咱们改变valueCopy
的值,它不会影响原来的value
值。同理,当咱们改变原来的值它也不会影响拷贝后的值。很好👍ui
let value = 3;
let valueCopy = value; // create copy
console.log(valueCopy); // 3
// Change valueCopy
valueCopy = 100
console.log(valueCopy); // 100
// ✅ Original NOT affected
console.log(value); // 3
复制代码
好的,这里就会有点奇怪了!咱们用一样的方法拷贝数组。spa
let array = [1,2,3];
let arrayCopy = array; // create copy
console.log(arrayCopy); // [1,2,3];
// Change 1st element of the array
arrayCopy[0] = '👻';
console.log(arrayCopy); // [ '👻', 2, 3 ]
// ❌Original got affected
console.log(array); // [ '👻', 2, 3 ]
复制代码
为何原来的数组也受到了影响呢?好了,是由于:你拷贝的不是你拷贝的。说人话,意思就是你拷贝的只是指向数组内存空间的指针。引用类型不包含值,它们是指向内存中值的指针。指针
解决方法就是拷贝值而不是指针。code
let array = [1,2,3];
let arrayCopy = [...array]; // create TRUE copy
console.log(arrayCopy); // [1,2,3];
// Change 1st element of the array
arrayCopy[0] = '👻';
console.log(arrayCopy); // [ '👻', 2, 3 ]
// ✅ Original NOT affected
console.log(array); // [ 1, 2, 3 ]
复制代码
当我使用展开扩展符号...
来拷贝一个数组,我只是浅拷贝了一个数组。若是数组是嵌套或者多维的,这就不奏效了。cdn
let nestedArray = [1, [2], 3];
let arrayCopy = [...nestedArray];
// Make some changes
arrayCopy[0] = '👻'; // change shallow element
arrayCopy[1][0] = '💩'; // change nested element
console.log(arrayCopy); // [ '👻', [ '💩' ], 3 ]
// ❌ Nested array got affected
console.log(nestedArray); // [ 1, [ '💩' ], 3 ]
复制代码
如上,浅拷贝首层数组表现良好,然而,更改了嵌套数组元素,原始数组也受到影响💩。为了解决这个问题,就要用到深拷贝了。blog
let nestedArray = [1, [2], 3];
let arrayCopy = JSON.parse(JSON.stringify(nestedArray));
// Make some changes
arrayCopy[0] = '👻'; // change shallow element
arrayCopy[1][0] = '💩'; // change nested element
console.log(arrayCopy); // [ '👻', [ '💩' ], 3 ]
// ✅ Nested array NOT affected
console.log(nestedArray); // 1, [ 2 ], 3 ]
复制代码
因此,这就完事了吗?要不要手写一个深拷贝引用类型的方法?ip
const deepClone = obj => {
const isObject = args => (typeof args === 'object' || typeof args === 'function') && typeof args !== null
if (!isObject) throw new Error('Not Reference Types')
let newObj = Array.isArray(obj) ? [...obj] : { ...obj }
Reflect.ownKeys(newObj).map(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}
复制代码
✅ ✅ ✅内存