[JS] Array.fill([]) 함수와 Copy by Value, Reference

2020. 6. 20. 13:42Javascript/시행착오

 1. Array.fill([])

   자료구조 책을 보고 기수정렬을 프로그래밍할 때 였다. 기수 정렬 포스팅에서는 버킷이라는 객체를 만들때 오브젝트 자체를 생성했지만, 원래는 이 차원 배열을 만들려고 했었다. 하지만 그러지 못했다. 왜냐하면 Array.fill([]) 함수 때문이었다. 다음 프로그램을 보자.

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

arr[0].push(1);

/* 이 함수의 출력은? */
console.log(arr);


/* 정답 */
/* [ [1], [1], [1] ] */

 

 위 프로그램의 출력 결과는 무엇일까? 나는 arr의 첫 번째 원소 배열에만 1이라는 요소가 추가될 줄만 알았다. 하지만 결과는 아니었다. 모든 원소 배열에 1이 추가됐던 것이다. 내가 키워드를 잘 못 입력했는지, 구글링을 해도 찾을 수가 없었다. 그래서 노마드 코더 슬랙에 다음과 같은 질문을 올렸다.

 

 

 너무나 감사하게도 Ander 님께서 다음과 같은 답변을 달아주셨다.

 

 

 한 가지 알았던 것은 fill이라는 함수 특성 때문이었다. Ander 님에 따르면, fill이라는 함수를 이용해서 만든 것은 사실 하나고, 나머지는 다 참조 값이라고 하셨다. 이 내용을 확인하기 위해 Array.from() MDN 사이트를 들어가보았다.

 

 

 설명란을 보니, fill 함수는 값을 복사하지 않고 객체를 참조한다고 써있다. 그래서 안됐던 것이다. Ander 님이 링크해주신 스택 오버 플로우 사이트를 보면, 내가 원했던 기능을 구현하기 위해서는 Array.from() 메소드를 이용하면 된다고한다. 그런데 질문을 보면 copy by value, copy by reference라는 용어가 있다. 이 두 용어는 무엇일까?

 

 

2. Copy By Value   VS   Copy By  Reference

 자바스크립트의 데이터 타입은 크게 두 종류로 나뉜다. 첫 번째는 객체타입이다. 객체 타입에는 Object, Array, function이 있다. 두 번째는 원시 자료형이다. 원시 자료형객체 타입을 제외한 모든 자료형을 말한다.

 

 

 이제 본론으로 들어가서 Copy By Value가 무엇인지 알아보자. Copy By Value복사할 대상을 새롭게 만든 변수에 그 값 자체를 할당한다라는 뜻이다. 다음 예시를 보자.

let a = 5;
let b = a;
a = 3;

console.log(a); // 3
console.log(b); // 5

 

 중간에 a의 값을 변경하였음에도 불구하고, b의 값에 전혀 영향을 끼치지 않고 서로 독립적인 값을 갖고 있다. 그 이유는 메모리가 각 변수에 할당되있기 때문이다. a의 메모리, b의 메모리의 주소가 모두 다르기 때문이다. Array.from() MDN 사이트를 들어가서 리턴 값을 보면

 

 

 리턴 값이 새로운 배열 인스턴스라는 것을 알 수 있다. 이제 Array.from을 이용해서 2차원 배열을 만들어서 값을 할당해보자.

let arr = Array.from({length: 3}, e => []);

arr[0].push(1);
console.log(arr);


/* 출력 결과 */
/* [ [1], [], [] ] */

 

 출력 결과를 보면 첫 번째 원소 배열에만 1이 삽입되있는 것을 알 수 있다. 이로써 우리는 Array.from() 함수Copy By Value 방식으로 돌아간다는 것을 알 수 있다.

 

 

 다시 본론으로 돌아오자. 그렇다면 Copy By Reference는 무엇을 말하는 걸까? Copy By Reference는 새로 만든 변수에 복사할 대상이 참조하고 있는 메모리 주소 값을 할당하는 방식을 말한다. 다음 프로그램을 보자.

const a = {
  'number': 0
}

const b = a;

b.number = 3;

console.log(a);
console.log(b);

 이 프로그램의 출력 결과를 보면 a, b의 속성 number의 값이 모두 3인 것을 확인할 수 있다. 왜냐하면 둘 다 내부적으로 같은 객체를 참조하고 있기 때문이다. b는 a값을 할당받은 것이 아니라 그저 a를 참조한 것이기 때문에 독립적으로 움직이지 않고, a에 대하여 종속적으로 움직인다.

 

 

 좀 더 쉽게 설명하기 위해 를 들어보도록 하겠다. 여러분은 배고파서 족발을 배달시켜 먹으려고한다. 동네에는 a라는 족발집과 b라는 족발집이 있다. 여러분은 지난 번에 a라는 족발집에 족발을 시켜먹은 적이 있지만, 형편 없던 맛에 기분이 매우 불쾌했던 기억이 있다. 그래서 이번에는 b라는 족발집에 전화를 했다.

 

 

 그런데, b 족발집에 전화를 해보니, 어디선가 많이 들어 본 목소리가 났다. 하지만 여러분은 기분 탓이라고 스스로 합리화를 한 후에 족발을 시켰다. 몇 분이 지난 후, 여러분이 시킨 족발이 왔다. 그리고 족발을 뜯고 나무젓가락을 보니 나무젓가락에는 a 족발이라는 상표가 있었다. 여러분은 깨달았다. b족발은 이름만 다르지 사실은 a 족발이라는 것을... 젠장;

 

 

 이러한 원리가 바로 Copy By Reference다.  따라서 Array.fill() 함수는 Copy By Reference 방식으로 동작하기 때문에 첫 번째 원소 배열에 1값을 넣으니, 모든 배열에 1이라는 원소 값이 삽입되었던 것이다.

 

 

3. 마치며

 공부를 하고 프로그램을 조금씩 짜보면서 자신감이 생겼는데, 아직 할 것도 많고 알아야 할 것도 많다는 것을 다시 한 번 느낀다. 하지만 하나하나 알아가는 과정에 나는 즐거움을 느끼고 설레임을 느낀다. 

 

 

4. 참고자료