Javascript 二维数组

Javascript 二维数组,javascript,arrays,reactjs,Javascript,Arrays,Reactjs,我使用下面的代码创建一个最初填充了false的布尔值的二维数组,然后分别翻转该值 constructor(props) { super(props); this.state = { fullGrid: Array(3).fill(Array(5).fill(false)) }; this.toggleFullGrid = this.toggleFullGrid.bind(this); } //Toggles boolean value found at id togg

我使用下面的代码创建一个最初填充了false的布尔值的二维数组,然后分别翻转该值

constructor(props) {
  super(props);

  this.state = {
    fullGrid: Array(3).fill(Array(5).fill(false))
  };
  this.toggleFullGrid = this.toggleFullGrid.bind(this);
}

//Toggles boolean value found at id
toggleFullGrid(cols, rows) {
  alert("This is index.js, we got everything: " + cols + " " + rows);
  let alteredGrid = this.state.fullGrid;
  console.log(alteredGrid);
  console.log(cols + " " + rows);
  console.log(alteredGrid[cols][rows]);

  //change alteredGrid at cols,rows
  alteredGrid[cols][rows] = !alteredGrid[cols][rows];
  console.log(alteredGrid);

  this.setState({fullGrid: alteredGrid});
}
但是,这会导致整个列以非常混乱的方式翻转,而不是翻转单个值。以下是控制台输出:

(3) [Array(5), Array(5), Array(5)]
  0 : (5) [true, false, false, false, false]
  1 : (5) [true, false, false, false, false]
  2 : (5) [true, false, false, false, false]
  length : 3
  __proto__ :  Array(0)

index.js:21 0 0

index.js:22 false

index.js:26 
(3) [Array(5), Array(5), Array(5)]
  0 : (5) [true, false, false, false, false]
  1 : (5) [true, false, false, false, false]
  2 : (5) [true, false, false, false, false]
  length : 3
  __proto__ : Array(0)
第一个数组是翻转前的一个副本,所以我不确定为什么它不全是假的。第二个和第三个输出证明程序知道它在翻转什么和在哪里。第四个输出第二个阵列与第一个阵列相同

此外,它也不是真正的更新。状态更改应该强制其他元素根据它们是否对应于数组中的true或false进行更新和更改颜色,但这不会发生

问:为什么要翻转整个专栏?为什么第一个输出的数组与第二个输出的数组相同?我如何让它翻转单个值?我如何让它正确更新


另外,有人告诉我,在javascript中,当试图翻转值时,数组会发生奇怪的事情,所以我测试了一个版本,在这个版本中,我将数组值保存到一个单独的变量,翻转它,然后将它保存回来。结果是相同的。

似乎是您使用Array.fill的方式导致了问题

原因是,只有一行在内部被引用了三次。因此,当您更改任何行中的任何单元格时,其他行中的特定单元格也会更改

可以按如下方式使用数组填充:

this.state = {
  fullGrid : Array(3).fill(0).map(row => new Array(5).fill(false))
}
上面的解决方案将首先创建一个0的数组,然后用一个新数组映射每一行,您可以在其中填充false

您还可以测试:

var a =  new Array(3).fill(new Array(5).fill(false));
(3) [Array(5), Array(5), Array(5)]
  0 : (5) [false, false, false, false, false]
  1 : (5) [false, false, false, false, false]
  2 : (5) [false, false, false, false, false]
  length : 3
  __proto__ :  Array(0)
如果你这样做

a[0][0] = true
现在a将成为:

(3) [Array(5), Array(5), Array(5)]
  0 : (5) [true, false, false, false, false]
  1 : (5) [true, false, false, false, false]
  2 : (5) [true, false, false, false, false]
  length : 3
  __proto__ :  Array(0)
由于该值是通过引用更改的,因此每行的第一个单元格都变为true

您的console.log输出是相同的,因为console.log以异步方式发生


欢迎来到神奇的sic!Javascript数组、引用和可变对象的世界

回答:为什么要翻转整个专栏

数组的工作方式不同于复制数据的简单值布尔值、字符串和数字。当您为一个变量分配一个数组时,您只分配了它的引用,而不是实际的对象。javascript中的所有非原语值都是对象

所以按照你写的:

Array3.fillArray5.fillfalse是两个语句:

Array5.fillfalse 阵列3.填充。。。 在第一个数组中,创建一个填充false的Array5,在第二个数组中,使用相同的Array5填充新的Array3 3次

因此,当您更改数组[0][0]时,实际上是在修改它后面的同一个对象,并且您发现自己更改了三个不同的引用,但仍然是相同的,并且只有以前创建的数组5

回答:为什么第一个输出的数组与第二个输出的数组相同

因为console.log不会冻结显示的值,而且如果它通常适用于简单值,则不会立即冻结。在控制台中打印值所需的时间,原始数组已被更改。由于打印引用,此引用将反映应用于其值的更改

我很抱歉,如果它不是真正可以理解的,因为我很难正确地解释它是如何作为英语工作的,因为它不是我的母语

回答:我如何让它翻转单个值?我如何让它正确更新

您需要使用不可变的值

首先,创建一个真正不可变的状态:

const array5 = Array(5).fill(false);
this.state = {
    fullGrid: Array(3).fill(null).map(() => array5.slice())
};
然后,在处理您的状态时,还要复制要处理的新阵列:

let alteredGrid = this.state.fullGrid.slice();
现在,您可以安全地设置新的清洁状态,该状态将正确替换旧状态