Programming/Client

[Javascript] Array.fill()로 2차원 배열을 만들면 안되는 이유

Jiwoo 2022. 5. 2. 15:57

🤔 문제 상황

[[], [], []] 와 같은 2차원 배열을 만들기 위해 코드를 작성하는 중이었다

let arr = new Array(3).fill([]);

위와 같이 Array() 생성자로 배열을 만들고 array.fill()을 이용해 안을 배열로 채웠다.
그리고 나서 arr[0]에만 숫자 1을 추가하려했다.

let arr = new Array(3).fill([]);

arr[0].push(1);

console.log(arr); // [[1], [1], [1]]

그런데 결과는 내 예상 밖이었다.
모든 배열에 숫자가 추가된 것이다.
처음에는 new Array() 생성자가 원인이라고 생각했으나 fill()이 원인이었다.


✅ array.fill()

arr.fill(value[, start[, end]])

  • value : 배열을 채울 값
  • start : 시작 인덱스 (기본값 0)
  • end : 끝 인덱스 (기본값 this.length)
[1, 2, 3].fill(4);               // [4, 4, 4]
[1, 2, 3].fill(4, 1);            // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);         // [1, 4, 3]

주의사항

value로 reference type(object, array, fnc)이 전달되면 참조값(값이 저장된 메모리 주소)가 저장됨

reference type이 뭐냐면...

데이터 타입에는 두 가지 종류가 있다.
바로 원시 자료형과 참조 자료형이다.
둘은 메모리에 저장되는 방식이 다르기 때문에 변수 선언 및 할당 시, 유의해야 한다.

  • 원시 자료형
    변수 선언, 초기화, 할당시 값이 저장된 메모리 영역에 직접 접근
    → 할당 시, 값만 읽어와서 복사/ 새 값이 할당되면 메모리에 저장된 값을 바로 변경
    ex) Number, string, Boolean, Null, Undefined

  • 참조 자료형
    변수에 할당시, 메모리의 주소값이 저장
    → 할당 시, 값을 복사하는 것이 아니라 주소값이 복사되어 같은 데이터를 참조하게 됨
    ex) Object , Array, Function

자세하게 잘 쓰인 글이 있어서 링크를 남기겠다.
webclub.tistory.com


✅ 결론

고로 fill()의 값으로 참조 자료형인 배열이 전달되면 각기 다른 배열이 할당되지 않고,
하나의 배열이 생성되고 그 주소가 할당된다.
고로 하나의 배열을 각 요소가 공유하게 된다는 것이다.
그래서 arr[0]에 추가해도 arr[1], arr[2]에도 값이 추가되었다.

배열 안에 참조 자료형을 채우고 싶을 때는 array.fill()을 사용하지 않는 것이 좋겠다.

2차원 배열을 만드는 방법

// 초기값 할당
let arr = [[], [], [] ...];

// 1. 반복문 사용
let arr = new Array(n); 
for (var i = 0; i < arr.length; i++) { 
    arr[i] = new Array(n); 
    // arr[i] = []; 속 배열 비어있다면 
}

// 2. ES6 지원 브라우저라면
// 2차원 배열 틀 생성 [[],[],[]] 
let arr = Array.from(Array(n), () => []); 
// arr[i][j] (빈 배열 생성) 
let arr = Array.from(Array(i), () => new Array(j)); 
// arr[i][j] (null로 초기화하여 생성) 
let arr= Array.from(Array(i), () => Array(j).fill(null));

확장성을 위해서 2, 3번을 주로 사용하는데 성능과 속도는 2번이 더 미세하게 빠르다.