Заполнить массив объектами с помощью цикла

Мне нужно создать массив, заполненный объектами. Допустим, { foo: 0}. Затем я хочу добавить свойство bar к каждому объекту с разным значением. Например: значение = индекс элемента в массиве.

Это выглядит так

const table = new Array(10).fill({foo: 0});

for (let i = 0; i < table.length; i += 1) {
    table[i].bar = i;
}

Я ожидал получить:

[
    { foo: 0, bar: 0 },
    { foo: 0, bar: 1 },
    { foo: 0, bar: 2 },
    ...
    { foo: 0, bar: 9 }
]

И что у меня получилось:

[
    { foo: 0, bar: 9 },
    { foo: 0, bar: 9 },
    { foo: 0, bar: 9 },
    ...
    { foo: 0, bar: 9 }
]

Почему он так себя ведет? Где я ошибся?

ДЕМО

РЕДАКТИРОВАТЬ Чтобы уточнить

Я не хочу заменять объекты в массиве новым объектом, например table[i] = {foo: 0, bar: i}. Он создает новый объект, который заменяет старый. Я просто хочу добавить свойства к существующему объекту.

Причина этого в том, что значение, которое вы привязываете к атрибуту bar, - я, которое в конце цикла равно 9, которое будет привязано к каждому экземпляру цикла.

Miaan 24.07.2018 17:20

@Miaan Это неверно. Это потому, что массив заполнен одним и тем же объектом, поэтому, когда вы меняете что-либо в массиве, вы меняете их все. Чтобы увидеть эту проблему, цикл не нужен.

Reinstate Monica Cellio 24.07.2018 17:29

Да, Арчер прав.

D. Seah 24.07.2018 17:29

Я понимаю, что происходит, я просто не умею объяснять

Miaan 24.07.2018 17:31

@Miaan Вставьте это в консоль, а затем проверьте результаты ... var table = new Array(10).fill({foo: 0}); table[3].bar = 25; console.info(table); (обратите внимание, что он меняет только одно свойство - никакого отношения к циклам)

Reinstate Monica Cellio 24.07.2018 17:32
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
5
874
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ваш массив имеет ссылку на один единственный объект. Итак, что происходит, вы обновляете один и тот же базовый объект. Если вы знакомы с C, это будет похоже на наличие N указателей на один и тот же базовый объект. Независимо от того, с каким указателем N вы работаете, вы измените базовый базовый объект.

const table = new Array(10)

for (let i = 0; i < table.length; i += 1) {
   table[i] = {foo: 0, bar: i}
}

Это создаст новый объект для каждой записи в вашем массиве

Ладно, я понял. Но я не хочу сразу заполнять массив. Я хочу добавить новые свойства к существующим объектам в массиве без изменения других свойств.

m51 24.07.2018 17:26

@kotlet Создайте массив, как указано выше, просто удалите свойство bar. Затем вы можете добавить и заполнить bar позже, как и ожидалось.

Reinstate Monica Cellio 24.07.2018 17:31

ИМХО, вы ищете что-то вроде этого:

const table = new Array(10);

for (let i = 0; i < table.length; i += 1) {
    table[i] = {'foo': 0, 'bar': i};
}

console.info(table)

Одно лайнерное решение с использованием ECMAScript-6:

const table = Array.from(new Array(10).keys()).map(e => ({'foo': 0, 'bar': e}))

console.info(table)
Ответ принят как подходящий

Array.fill() принимает значение и заполняет им массив. Поскольку непримитивы (объекты, массивы) передаются по ссылке, модификация любого элемента приведет к изменению и остальных.

Вместо этого вы можете использовать Array.from() и передать объект его функции сопоставления:

const table = Array.from({length:10}, _ => ({foo:0}));

for (let i = 0; i < table.length; i += 1) {
    table[i].bar = i;
}

console.info(table);

Другие вопросы по теме