Array.fill() 메서드는 이름 그대로 첫 번째 인자에 주어진 값으로 배열의 모든 요소를 채우는 메서드다. 주로 Array() 생성자와 함께 사용하여, 초기값이 할당된 배열을 생성할 때 유용하게 쓰인다.

Array.fill(value, start?, end?)

// length가 2인 빈 배열 생성 후 null로 채움
const filledArray = Array(2).fill(null);
console.log(filledArray); // [null, null]

const numbers = [1, 2, 3, 4];
// 2~3번 인덱스를 null로 채움 (start 포함, end 미포함)
numbers.fill(null, 2, 4);
console.log(numbers); // [1, 2, null, null]

이때 주의할 점은, 배열의 모든 요소는 fill(value) 메서드 첫 번째 인자로 전달한 value 값을 가리킨 다는 것이다. 만약 value가 객체라면 모든 요소는 동일한 객체를 참조하게 된다.

const arr = Array(2).fill({ name: "John" });
console.log(arr); // [{ name: 'John' }, { name: 'John' }]
console.log(arr[0] === arr[1]); // true

함수를 사용해 값을 생성하고 fill() 인자로 넘겨도 결과적으로 배열내 모든 요소는 동일한 참조 값을 공유한다. 아래 예제의 getUser() 함수는 호출될 때마다 새로운 객체를 생성하고 반환하지만, fill() 인자에서 사용하면 단 한 번만 호출되며, 생성된 객체는 배열의 모든 요소에 할당된다.

const getUser = (name = "John") => {
  console.count("getUser"); // getUser: 1 (1회 호출)
  return { name };
};

const arr = Array(2).fill(getUser());
console.log(arr); // [{ name: 'John' }, { name: 'John' }]
console.log(arr[0] === arr[1]); // true

각 요소가 독립적인 객체를 가져야 하는 경우 fill() 메서드 보단, Array.from() 정적 메서드를 사용하는게 더 적절하다. Array.from() 메서드는 유사배열 혹은 이터러블을 받아 얕은 복사 후 새로운 배열을 생성하는데, 두 번째 인자로 매핑 함수를 넘길 수 있다.

Array.from(arrayLike, mapFn(element, index)?)

const getUser = (name = "John") => {
  console.count("getUser"); // getUser: 2 (2회 호출)
  return { name };
};

// length가 2인 배열을 생성하고 각 요소에 getUser 함수를 호출하여 객체 생성
const arr = Array.from({ length: 2 }, getUser);
console.log(arr); // [{ name: 'John' }, { name: 'John' }]
console.log(arr[0] === arr[1]); // false