为什么对单元格所做的更改会传播到使用fill创建的这个二维数组中的其他单元格?

时间:2017-07-07 05:05:05

标签: javascript arrays

我在JS中遇到这个二维数组的问题。当我更改a[1][0]时,a[0][0]会随之更改。我初始化它的方式有什么问题吗?如果是,我该如何正确初始化它?

>var a = Array(100).fill(Array(100).fill(false));
>a[0][0]
>false
>a[1][0]
>false
>a[1][0] = true
>true
>a[1][0]
>true
>a[0][0]
>true

7 个答案:

答案 0 :(得分:17)

var a = Array(100).fill(Array(100).fill(false));

a包含一个数组,每个数组都引用一个数组。您正在使用包含所有错误值的数组填充外部数组。内部数组只进行一次,并且对同一数组的引用被传递给外部数组的每个元素,这就是为什么如果对一个元素执行操作,它也会反映在其他元素上。

这实际上相当于

var a1 = Array(100).fill(false);
var a = Array(100).fill(a1);

此处a获取100个元素,所有元素都引用相同的数组a1。因此,如果更改a的一个元素,则所有元素都会更改,因为它们是对同一数组的引用。

您需要使用新数组填充外部数组中的每个元素。你可以这样做:

var a = [];
for(var i=0; i<100; i++)
  a.push(Array(100).fill(false));

答案 1 :(得分:7)

您的整个数组将填充对相同(第二维)数组对象的引用。

要用不同的对象填充它,你必须做这样的事情:

&#13;
&#13;
const a = Array(100).fill(false).map(x => Array(100).fill(false));

a[0][0] = true;

console.log(a[0][0]);
console.log(a[0][1]);
console.log(a[1][1]);
&#13;
&#13;
&#13;

请注意,初始数组中的值需要显式设置为某些内容(在我的示例false中,但也可能是undefined),因为构造函数创建的数组是稀疏的并且map()函数仅对实际存在的属性进行操作。

要解决此问题,您可以使用Array.from()

&#13;
&#13;
const a = Array.from(Array(100), x => Array(100).fill(false));

a[0][0] = true;

console.log(a[0][0]);
console.log(a[0][1]);
console.log(a[1][1]);
&#13;
&#13;
&#13;

答案 2 :(得分:3)

您的问题是您在第一个阵列的每个位置使用第二个Array(100).fill(false)。这就是为什么当你在&#34;第二个&#34;中更改一个值时尺寸将在阵列的每个位置发生变化。如果你想避免这种情况,你必须为初始的每个位置创建一个新的数组。

var x = Array(100).fill().map(x => Array(100).fill(false));

答案 3 :(得分:2)

你在这里做的是在更大数组的每个索引处添加相同的数组对象。

所以当你这样做时

Array(x).fill(Array(y).fill(false));

你实际做的是:

Array(x).fill(Y); // i.e. X.fill(Y)

现在,无论何时更改Y,您都会在X的每个索引处获得相同的值。

当数据本身是一个对象时,你应该使用循环来填充数据(记住Array是对象)。

答案 4 :(得分:1)

这些似乎是一个重复的问题,但我总是只使用这样的东西

var x = new Array(10);
for (var i = 0; i < 10; i++) {
  x[i] = new Array(10).fill(false);
}
x[5][5] = true

信用:How can I create a two dimensional array in JavaScript?

答案 5 :(得分:1)

由于数组是引用类型,因此在JS中创建N维数组并不是那么简单。您需要先创建一个克隆工具。

&#13;
&#13;
Array.prototype.clone = function(){
  return this.map(e => Array.isArray(e) ? e.clone() : e);
};

function arrayND(...n){
  return n.reduceRight((p,c) => c = (new Array(c)).fill().map(e => Array.isArray(p) ? p.clone() : p ));
}

var arr = arrayND(2,3,4,"x")
console.log(JSON.stringify(arr));
&#13;
&#13;
&#13;

arrayND采用无限数量的整数参数,每个参数指定一个维度的大小,最后一个参数是填充值。

答案 6 :(得分:0)

mdn中描述的fill函数将相同的值复制到所有数组索引。您可以使用以下实用程序来创建阵列的克隆。但由于我使用切片运算符,因此仅限于克隆数组。

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/fill

   if (!Array.prototype.clonefill) {
  Object.defineProperty(Array.prototype, 'clonefill', {
    value: function(value) {

      // Steps 1-2.
      if (this == null) {
        throw new TypeError('this is null or not defined');
      }

      var O = Object(this);

      // Steps 3-5.
      var len = O.length >>> 0;

      // Steps 6-7.
      var start = arguments[1];
      var relativeStart = start >> 0;

      // Step 8.
      var k = relativeStart < 0 ?
        Math.max(len + relativeStart, 0) :
        Math.min(relativeStart, len);

      // Steps 9-10.
      var end = arguments[2];
      var relativeEnd = end === undefined ?
        len : end >> 0;

      // Step 11.
      var final = relativeEnd < 0 ?
        Math.max(len + relativeEnd, 0) :
        Math.min(relativeEnd, len);

      // Step 12.
      while (k < final) {
        O[k] = value.slice(0);
        k++;
      }

      // Step 13.
      return O;
    }
  });
}
Array(100).clonefill(Array(100))
a[0][0] = true
a[1][0]
false