[JavaScript] 값 vs 레퍼런스

  • 이 책은 You Don’t Know JS, 카일 심슨 저, 한빛미디어 를 공부하며 작성한 글입니다.
  • 단순히 블로그만 읽는 것은 추천하지 않습니다.

[들어가기 전]

기존에 공부하였던 C++를 기준으로, 값은 사용하는 구문에 따라 값-복사나 레퍼런스-복사의 형태로 할당/전달 한다.

즉, int a = 4; 라는 구문을 통해 int형의 메모리 공간을 선언하고, 그 안에 값으로 4를 넣는다던지,

혹은 int &ref = a; 나 int *ptr = &a 등의 구문으로 a의 참조자를 만들거나, a를 가리키게 할 수 있었다.

자바스크립트는 포인터라는 개념 자체도 없고 참조하는 방법 역시 다르다.

우선 어떤 변수가 다른 변수를 참조할 수 없다. 하나씩 살펴보자.

[값과 레퍼런스]

자바스크립트에서 레퍼런스는 공유된 값을 가리킨다.

공유된 값이 무슨 의미일까?

자바스크립트는 값의 타입으로, 값-복사 나 레퍼런스-복사가 결정된다.

null, undefined, string, number, boolean, symbol 등의 단순 값은 언제나 값 복사 방식으로 할당/전달 된다.

반면, 객체, 함수 등 합성 값은 할당/전달 시 반드시 레퍼런스 사본을 생성한다.

즉, 값을 넣을 공간을 내가 결정하고 선언하여 값을 넣는 것이 아닌, 값 자체의 자료형에 따라 결정된다는 것!

이 부분이 나는 이해하는데 시간이 오래 걸렸다…

코드를 봐보자

let a = 2; //2는 number이기 때문에 값 복사 방식으로 할당/전달 된다.
let b = a; // 역시 a의 값이 복사되어 b로 전달됨.
b++;
console.log(a); //2
console.log(b); //3

let c = [1,2,3]; //배열은 레퍼런스를 통해 할당/전달 된다.
let d = c;
d.push(4);
console.log(c); // [1,2,3,4]
console.log(d); // [1,2,3,4]

변수 c와 d에 대해서 생각해보자. 이 부분이 조금 헷갈릴 수 있는데, c와 d는 [1,2,3] 을 소유하는 것이 아닌, 이 값을 “동등”하게 참조하는 것이다

동등하게 참조한다는 말이 무슨 말인지부터 생각을 해봐야 한다.

int arr[4] = {1,2,3};
int *ptr = arr;

이 경우에 배열 값을 저장하기위한 int형 메모리 공간 3칸을 마련하고, 그 곳에 1,2,3을 먼저 대입한 후, arr이라는 주소값을 붙히게 된다.

그리고, arr을 가리키는 포인터 변수 ptr을 선언하는 것.

반면 동등하게 참조한다는 것은, [1,2,3]의 공유된 단일 값이 먼저 할당 되고, c와 d가 동등한 위치에서 [1,2,3] 을 참조하고 있다는 것이다.

따라서, 이 경우 실제 공유한 배열 값이 변경되면(push(4)), 이 공유 값을 참조하는 두 레퍼런스 모두 [1,2,3,4]를 바라보게 된다.

다음 코드를 봐보자.

let a = [1,2,3];
let b = a;
console.log(a); // [1,2,3]
console.log(b); // [1,2,3]
b = [4,5,6];
console.log(a); // [1,2,3]
console.log(b); // [4,5,6]

이 경우는 위의 코드와 조금 관점을 달리해서 봐야한다.

레퍼런스는 변수가 아닌 값 자체를 가리키므로, a 레퍼런스로 b 레퍼런스가 가리키는 대상을 변경할 수 없다.

b = [4,5,6] 으로 재할당을 하면, b는 그저 [4,5,6]을 참조하게 되고,

a 는 여전히 [1,2,3]을 참조하고 있는 것이다.

위의 push(4) 코드를 통해 a와 b가 참조하는 곳 자체의 값을 변경하는 것과는 다르다.

책에는 이에 대한 예방, 해결방법 등이 나와있지만 이에 대해서는 추후 공부를 더 하고 난 후에 포스팅을 하도록 하겠다.

출처

You Don’t Know JS, 카일 심슨 저, 한빛미디어

댓글남기기