Разный результат при одинаковых операциях с массивом объектов

Создаю массив объектов:

const arr1 = [{}, {}, {}, {}];
const arr2 = Array(4).fill({});

Добавляю свойство в объект:

arr1[1].One = '1'; 
arr2[1].One = '1'; 

Проверяю arr1:

0: {};
1: {One: '1'};
2: {};
3: {};

Проверяю arr2:

0: {One: '1'};
1: {One: '1'};
2: {One: '1'};
3: {One: '1'};

Почему так?


Ответы (2 шт):

Автор решения: SwaD

Array(4).fill({}) создаст массив с 4 элементами и в каждый положит ссылку на ОДИН объект.

Т.к. объекты передаются по ссылкам, то присваивание одного объекта разным переменным делает эти переменные равными друг-другу. Другими словами, все такие переменные смотрят на один объект.

Проверить можно на примере ниже:

const a = { one: 2 }
const b = a; // Передали по ссылке. b теперь ссылается на a
b.one = 1;

console.log('Равны', a === b);
console.log(a, b);

const c = { one: 2 };
const d = { one: 2 }; // Cоздали новый объект

console.log('Не равны', c === d);
console.log(c, d);

Зная это, метод fill, в вашем примере, можно представить как:

const obj = {};
array.fill(obj);

Метод fill сначала получает значение, которое надо присвоить элементам и уже потом выполняет операцию присваивания. Поэтому получаем вот такой массив

[obj, obj, obj, obj]

Убедиться в этом можно так:

const arr2 = Array(4).fill({});
console.log(arr2[1] === arr2[3]); // Все элементы равны друг другу, т.к. объект один

arr2[3].one = 1;
console.log(arr2[1] === arr2[3]);
console.log(arr2[0], arr2[1], arr2[2], arr2[3]);

→ Ссылка
Автор решения: Deeps

Метод fill() заполняет все элементы массива от начального до конечного индексов одним значением.

Когда ты записываешь в переменную объект, ты записываешь ссылку на этот объект, а не сам объект. Соответственно, при копировании данных из одной переменной в другую переменную, будет копироваться ссылка, а не объект. А это значит, что при редактировании "скопированного" объекта будет редактироваться и первоначальный, так как обе переменных ссылаются на один объект

const a = {}
const b = a;

b.field = 1;

console.log(a) // {field : 1}

В функции fill() происходит примерно то же самое:

const array = [];
const argument = {}; // объект, переданный в функцию

// Всем полям задаётся одна и та же ссылка на объект, объект при этом не копируется
array[0] = argument;
array[1] = argument;
array[2] = argument;
array[3] = argument;

array[0].field = 1

console.log(array) // [{field: 1}, {field: 1}, {field: 1}, {field: 1}]

А когда ты сам инициализируешь массив объектами, ты создаёшь 4 разных объекта, не зависящих друг от друга

→ Ссылка