Почему изменения, внесенные в ячейку, распространяются на другие ячейки в этом двумерном массиве, создаваемом с помощью fill?

У меня проблема с этим двумерным массивом в 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

Ответ 1

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));

Ответ 2

Весь массив будет заполнен ссылками на тот же объект (второй размер) массива.

Чтобы заполнить его отдельными объектами, вам нужно сделать что-то вроде этого:

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]);

Ответ 3

Ваша проблема в том, что вы используете второй Array(100).fill(false) в каждой позиции первого массива. Поэтому, когда вы меняете одно значение во втором измерении, оно изменяется в каждой отдельной позиции массива. Если вы хотите этого избежать, вам нужно создать новый массив для каждой позиции исходного.

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

Ответ 4

то, что вы здесь делаете, добавляет один и тот же объект массива в каждый индекс большего массива.

Итак, когда вы делаете

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

В действительности вы делаете следующее:

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

Теперь, когда вы меняете Y, вы получите одинаковое значение при каждом индексе X.

Вы должны использовать цикл для заполнения данных, когда сами данные являются объектами (помните, что объект Array - это объект).

Ответ 5

Это похоже на дублированный вопрос, но я всегда использовал что-то вроде этого

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

Кредит: Как создать двумерный массив в JavaScript?

Ответ 6

Поскольку массивы являются ссылочными типами, создание N-мерного массива в JS не так тривиально. Сначала вам нужно создать инструмент клонирования.

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));

Ответ 7

Функция заполнения, как описано в mdn, копирует одно и то же значение во все индексы массива. Вы можете использовать утилиту ниже для создания клонов массива. Но так как я использую оператор slice, это ограничивается клонированием массивов.

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