【问题标题】:Have trouble doing push to a sub-array in a 2D JS array推送到 2D JS 数组中的子数组时遇到问题
【发布时间】:2022-01-21 00:28:20
【问题描述】:

假设我制作了一个由整数 9 填充的 5 x 2 矩阵 let arr = Array(5).fill(Array(2).fill(9));

现在我想通过执行将整数 8 推入矩阵的第四行 arr[3].push(8);

我最终得到了[[9,9,8],[9,9,8],[9,9,8],[9,9,8],[9,9,8]]。矩阵中的所有行都已推入 8。 为什么?

我发现如果我做了下面这样的事情,我得到了我想要的,但是为什么呢?

arr[3] = [...arr[3]];
arr[3].push(8);

【问题讨论】:

    标签: javascript multidimensional-array


    【解决方案1】:

    简短回答:这是因为所有 5 个数组都共享对完全相同数组的引用 即Array(2).fill(9) => [9,9]

    快速解决方案:使用Array.form为每一层创建一个deep-copy

    let arr = Array.from({length: 5}, e => Array(2).fill(9));
    

    或尝试这些答案中的任何其他解决方案(ref 1ref 2ref 3

    请参阅下面的工作解决方案(注意控制台中的浅拷贝)

    // PROBLEM
    
    // Shallow-copies
    let arr1 = Array(5).fill([...Array(2).fill(9)]);
    arr1[3].push(8);
    
    // writing to the document
    document.write('Shallow -> ', arr1)
    // loggin in console
    console.log('shallow ',  arr1)
    
    
    // SOLUTION
    
    // deep-copies
    let arr2 = Array.from({length: 5}, e => Array(2).fill(9));
    arr2[3].push(8);
    
    // writing to the document
    document.write('<br><br> Deep -> ', arr2)
    // loggin in console
    console.log('deep', arr2)

    详细信息:正如这里的文档(描述here 中的第5 点)中提到的,关于.fill 的第一个参数,这是您传入的数组,即[9,9]

    如果第一个参数是对象,则数组中的每个槽都会引用该对象。

    文档中也提到了确切的场景,请参阅此代码 sn-p here

    这表明所有项目基本上都是对同一个对象的引用 [也称为shallow copy],更改一个项目将导致其他所有项目都发生相同的变化。

    Array.from 修复了这个问题,因为Array(2).fill(9) 现在将在数组的每个元素上创建一个新数组。详细了解Array.fromhere


    你最后提到的这个修复是有效的,因为通过使用扩展运算符[...arr[3]],我们在第 4 个索引上创建了这个 [9,9] 数组的深层副本,这不是对同一个初始数组的引用 [ 9,9] 所以,现在在第 4 个索引处更改此项目只会更改第 4 个项目的数组本身。

    注意这个扩展运算符...arr 只创建了一个single level deep copy 所以,如果(假设)这个arr[3] 在其中包含另一个多级数组,那么只有第一级将被创建为深副本和所有内部副本将保留为浅副本[即对对象的相同引用]

    【讨论】:

      猜你喜欢
      • 2013-09-04
      • 1970-01-01
      • 2017-07-01
      • 2014-09-22
      • 1970-01-01
      • 2020-12-26
      • 2011-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多