V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
Turkestan
V2EX  ›  JavaScript

js 嵌套数组赋值问题

  •  
  •   Turkestan · 2022-01-01 15:19:33 +08:00 · 2095 次点击
    这是一个创建于 839 天前的主题,其中的信息可能已经有所发展或是发生改变。
    const arr = Array(2).fill(Array(2).fill(0));
    // arr = [[0, 0], [0, 0]]
    arr[1][1] = 1;
    
    // expected:
    [[0, 0], [0, 1]]
    
    // current:
    [[0, 1], [0, 1]]
    

    为啥给数组第二个元素里的最后一项赋值为 1 , 前一个元素里的末项也会变成 1

    正确解法没想到。。直接用上面第二行代码初始化二维数组,然后再进行赋值,完全没这个问题

    13 条回复    2022-01-03 19:15:48 +08:00
    dcsuibian
        1
    dcsuibian  
       2022-01-01 15:23:00 +08:00   ❤️ 1
    数组是引用、指针,arr[0]===arr[1]
    Turkestan
        2
    Turkestan  
    OP
       2022-01-01 15:31:43 +08:00
    用这种方法更新没问题:
    const arr = [...Array(n)].map(() => Array(n).fill(0))
    // arr = [[0, 0], [0, 0]]
    arr[1][1] = 1;

    console.log(arr)
    // [[0, 0], [0, 1]]

    没想通。。。
    Yukee798
        3
    Yukee798  
       2022-01-01 15:35:33 +08:00   ❤️ 1
    应该是 fill 方法的原因吧,Array(2).fill([0, 0]) 的时候,arr 里面存放的两个 [0, 0] 数组实际上是堆区里的同一个对象。
    如果直接用 arr = [[0, 0], [0, 0]],那么里面的两个 [0, 0] 数组在堆区里面是两个不同的对象。
    tedding
        4
    tedding  
       2022-01-01 15:35:37 +08:00 via iPhone   ❤️ 1
    arr[0] arr[1] 指向同一个位置啊。fill 填充字符串没这个问题,填充引用类型这就是正确的行为。
    Turkestan
        5
    Turkestan  
    OP
       2022-01-01 15:37:43 +08:00
    看了一下 MDN 对 fill 方法中 value 的解释:
    > Value to fill the array with. (Note all elements in the array will be this exact value.)

    所以第一种赋值方法展开来应该是这样的:

    arr[1][1] = 1;
    // 改变了初始化时括号内的 Array(2).fill(0),即改变了第一个 fill 方法的 value.
    arr[0] === arr[1] === Array(2).fill(0)
    // 因此,arr[1][1] 发生变化后,arr[0][1] 也跟着发生变化了
    tyx1703
        6
    tyx1703  
       2022-01-01 15:38:06 +08:00   ❤️ 2
    fill 填充是浅拷贝

    If the first parameter is an object, each slot in the array will reference that object.

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill#description

    我一般这样创建二维数组:

    Array.from(new Array(m), () => Array.from(new Array(n), () => 0));
    fengfuliu
        8
    fengfuliu  
       2022-01-01 15:59:18 +08:00
    原因就是 fill 参数为引用类型时操作会有这个问题;可以这样 Array(2).fill(0).map(item=>Array(2).fill(0))
    cansiny0320
        9
    cansiny0320  
       2022-01-01 16:30:43 +08:00
    const arr = new Array(2).fill(0).map(() => new Array(2).fill(0));
    muzuiget
        10
    muzuiget  
       2022-01-01 16:41:35 +08:00
    仔细看清楚 fill 的用法。
    dany813
        11
    dany813  
       2022-01-02 16:09:46 +08:00
    引用类型,不过挺有意思的,平时都注意不到
    2i2Re2PLMaDnghL
        13
    2i2Re2PLMaDnghL  
       2022-01-03 19:15:48 +08:00
    @tyx1703 准确地说 fill 填充不拷贝只复制引用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   919 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 22:15 · PVG 06:15 · LAX 15:15 · JFK 18:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.