코딩쌀롱

new Array(3).fill([ ]) 문제 본문

개발공부

new Array(3).fill([ ]) 문제

이브✱ 2020. 12. 20. 20:37

 

문제 발생

[코드스쿼드 마스터즈 문제 - 3단계. 루빅스 큐브 구현] 

큐브의 완전한 면을 3x3의 2차원 배열로 먼저 만들기 위해 arr1의 방식으로 6면을 만들었다.

그리고 큐브를 돌린 후 결과값을 다시 넣어줄 때 forEach 반복문을 돌리는데.. 문제가 발생했다.

3x3배열에서 오른쪽 열 값들을 바꾸기 위해 위의 forEach식을 사용했다.(오른쪽열이건 왼쪽열이건 똑같은 문제 발생함)

 

내가 예상했던 실행 과정

forEach 1번째 실행 [['O', 'O', 1], ['O', 'O', 'O'], ['O', 'O', 'O']]
forEach 2번째 실행 [['O', 'O', 1], ['O', 'O', 2], ['O', 'O', 'O']]
forEach 3번째 실행 [['O', 'O', 1], ['O', 'O', 2], ['O', 'O', 3]]

 

실제 실행 과정(디버깅)

forEach 1번째 실행 [['O', 'O', 1], ['O', 'O', 1], ['O', 'O', 1]]
forEach 2번째 실행 [['O', 'O', 2], ['O', 'O', 2], ['O', 'O', 2]]
forEach 3번째 실행 [['O', 'O', 3], ['O', 'O', 3], ['O', 'O', 3]]

한 번 실행할 때마다 안에 있는 배열들이 마치 같은 배열의 원소인냥 한 번에 같이 값이 바뀌었다.

결과값으로 2차원 배열의 오른쪽 열이 1, 2, 3이 아니라 3, 3, 3으로 나왔다.

 

문제 원인

문제는 fill()메서드의 인자에 있었다.

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

fill()메서드는 배열의 시작 인덱스부터 끝 인덱스의 이전까지 정적인 값 하나로 채운다.

매개변수 value는 배열을 채울 값, start는 시작 인덱스, end는 끝 인덱스이고, 변형한 배열을 반환한다.

중요한 것은, value에 객체를 받을 경우 그 참조만 복사해서 배열을 채운다는 것.

// Objects by reference.
var arr = Array(3).fill({}); // [{}, {}, {}]
arr[0].hi = "hi"; // [{hi: "hi"}, {hi: "hi"}, {hi: "hi"}]

필수 매개변수인 value에 어떤 데이터 타입이 들어가는지에 따라 매우 달라진다.

참조형 데이터를 넣을 경우에는 참조를 복사하기 때문에 결국 주소값이 같은 참조형 데이터로 배열이 채워진다. 따라서 배열의 한 원소만 바꾸려고 해도 모든 원소들이 같이 바뀐다.  내 코드를 다시 보면,

const arr = new Array(3).fill(new Array(3).fill('O'));

안쪽의 fill 메서드 안에는 문자열인 정적인 값을 넣었지만, 바깥의 fill 메서드 안에 배열(['O', 'O', 'O'])을 넣었다. 그렇기 때문에 forEach로 내부 배열의 값을 하나씩 변경할 때 모든 원소들이 같이 값이 바뀌었던 것이다.(같은 주소값)

 

해결 방법

제일 위의 사진에서 arr2처럼 배열리터럴로 직접 만들었다.

생각치도 못한 곳에서 문제가 발생했고, 문제 원인을 알아내는 데에도 시간이 꽤 걸렸다. 문제를 해결하는 것은 매우 간단했지만 문제 원인을 정확히 이해하는 것이 중요했던 것 같다.

 

 

Comments