欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

怎么使用javascript深度拷贝一个数组

程序员文章站 2023-01-10 08:46:52
有两种数组拷贝类型:浅拷贝 & 深拷贝。浅拷贝只会拷贝数组的第一层,剩下的会引用。如果你需要一个嵌套的数组的拷贝,那需要你去深度拷贝这个数组。深拷贝,选择json方法或者l...

有两种数组拷贝类型:浅拷贝 & 深拷贝。浅拷贝只会拷贝数组的第一层,剩下的会引用。如果你需要一个嵌套的数组的拷贝,那需要你去深度拷贝这个数组。深拷贝,选择json方法或者lodsh库吧

const numbers = [1, [2], [3, [4]], 5];
// using javascript
json.parse(json.stringify(numbers));
// using lodash
_.clonedeep(objects);

数组是引用类型

为了搞清楚为什么有两种类型的拷贝,我们来深度了解一下基础知识然后解释什么是引用类型。
与原始类型(number、string)不同,数组是引用类型。这意味着当你把一个数组赋值给一个变量,你是将数组的内存地址而非数组本身赋给变量。

拷贝值类型

这里没什么大不了的,我们创建一个value的拷贝。当我们改变valuecopy的值,它不会影响原来的value值。同理,当我们改变原来的值它也不会影响拷贝后的值。很好????

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

拷贝引用类型

好的,这里就会有点奇怪了!我们用同样的方法拷贝数组。

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 ]

为什么原来的数组也受到了影响呢?好了,是因为:你拷贝的不是你拷贝的。说人话,意思就是你拷贝的只是指向数组内存空间的指针。引用类型不包含值,它们是指向内存中值的指针。

拷贝引用类型的方法

解决方法就是拷贝值而不是指针。

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 ]

浅 & 深 拷贝

当我使用展开扩展符号...来拷贝一个数组,我只是浅拷贝了一个数组。如果数组是嵌套或者多维的,这就不奏效了。

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 ]

如上,浅拷贝首层数组表现良好,然而,更改了嵌套数组元素,原始数组也受到影响????。为了解决这个问题,就要用到深拷贝了。

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 ]

所以,这就完事了吗?要不要手写一个深拷贝引用类型的方法?

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
}

文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,