2016-12-13 3 views
4

Я сталкиваюсь с чем-то, чего не понимаю с помощью массива. В самом деле, я создал массив, который я заполнил пустыми подматрицами, чтобы получить 2D-матрицу. Но когда я манипулирую массивом, он не ведет себя так, как я ожидал.Странное поведение массива, заполненного Array.prototype.fill()

var arr = new Array(5); 
arr.fill([]); 
arr[2].push("third rank item"); 
console.log(arr); 

//[ [ 'third rank item' ], 
// [ 'third rank item' ], 
// [ 'third rank item' ], 
// [ 'third rank item' ], 
// [ 'third rank item' ] ] 

Каждый свет по этому вопросу будет приветствоваться

+0

Как вы ожидаете, что вести себя? – Feathercrown

+2

Вы заполняете ** тот же ** пустой массив. Вместо этого вы можете попробовать 'Array.from (новый массив (5),() => [])'. –

+0

@torazaburo Не могли бы вы объяснить это кратко? OP нацелил 3-й элемент во внешнем массиве и нажал строку, которая приводит к тому, что она нажимает строку во всех внутренних массивах. Немного смущает. –

ответ

5

Это та же самая старая проблема с массивами (и объекты в целом), являющихся ссылки, а не значений.

В частности, когда вы делаете arr.fill([]), вы берете один единственный пустой массив и используете его для заполнения родительского.

Это как сказать:

var arr = new Array(5); 
arr[0] = arr[1] = arr[2] = arr[3] = arr[4] = []; 

Все они относятся к одному массиву! Поэтому, когда вы затем изменяете один из них, похоже, что все они модифицированы (но на самом деле это все тот же)

К сожалению, нет простого способа присвоить пустой массив каждому из них. Вы могли бы сделать что-то вроде:

Array.apply(null, Array(5)).map(function() {return [];}); 

По сути, создать (инициализируется) пустой массив длины 5 и отобразить каждый (пусто) значение нового [].

EDIT: Похоже, я застрял в старые времена. В соответствии с комментарием @ torazaburo, вы можете использовать Array.from вместо Array.apply(null, Array(5)).map, например, так:

Array.from(new Array(5), function() { return []; }); 
+0

Спасибо за четкое объяснение и умное решение –

1

Как вы можете заметить, используя array.fill вы заполняете массив с ссылкой на тот же массив,

если вы хотите, чтобы каждый экземпляр индекса массива в пустой массив нормальный цикл в то время как будет делать:

var arr = []; 
 
var n = 5 
 
while(n--) 
 
    arr[n] = [] 
 

 
arr[2].push("third rank item"); 
 
console.log(arr);

Вариант 2:
если у вас есть lodash имеющегося пакета, вы можете также использовать _.map как это specificaly предназначен для петли через разреженный массив (нативный карта будет пропускать удобство инициализации значения)

var arr =_.map(new Array(5), (x => [])) 
 

 
arr[2].push("third rank item"); 
 
console.log(arr)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

+0

Спасибо за предоставление дополнительного решения с lodash –

1

Одиннадцатая строка ECMA doc файла Array.prototype.fill явно дает основание для тайны.

Повтор, в то время как к < конечная

Пусть Рк ToString (к).

Пусть setStatus будет установлено (O, Pk, значение, true).

ReturnIfAbrupt (setStatus).

Увеличить k на 1.

Здесь «значение» является только ссылкой. И они устанавливают его как свойство массива напрямую. Это означает, что все заполненные массивы относятся только к одному объекту массива.

+1

Thank's. Вы очень хорошо знаете о важности документации для чтения. –

1

Это бывает причина ссылки. Массив - это тип объекта, и объект работает над их ссылками, когда вы заполняете свой массив 0x, заполняете только те, которые выполняются, и помещаете один и тот же массив во все индексы, поэтому при обновлении подматрица все обновляются.

Решение:

let arr = new Array(5).fill(0).map(ele => ele = []); arr[2].push("something");

ИЛИ

let arr = Array.of([], [], [], []); arr[2].push("something");

Результат: как и ожидалось только 2 индекс arr обновляется.

+0

Быстро писать и легко понять. Спасибо –

+0

добро пожаловать. –

0

Вы можете попробовать это,

var arr = new Array(5); 
 
var i = 0; 
 
while (i < arr.length) 
 
    arr.fill([], i++); 
 
arr[2].push("third rank item"); 
 
console.log(arr);

0

Попробуйте, это быстрое решение для вас в одной строке.

var arr = new Array(5); 
 
arr = Array.from(arr, x => []); 
 
arr[2].push("third rank item"); 
 
console.log(arr);

Смежные вопросы