Javascript

🌟추천🌟원시값과 참조값, 그리고 mutate와 assignment

킹king 2020. 12. 26. 20:13
반응형

var num = 1;

var num2 = num;

num = 2;

console.log(num2) // 1

🤨?

 

var room = {
	table: 1
};

var room2 = room;

room.table = 2;

console.log(room2.table) // 2;

🤨??

 

 

둘의 차이점은 첫번째는 원시값(primitive)이고 다른쪽은 참조값(reference)라는 것.

 

 

원시값 primitive value/type

은 메모리에서 스택 stack이라는 공간에 값을 저장하게 됨.

 

스택에서는 비교적 짧은 데이터들을 저장하고 빨리 불러오며, '스택'이라는 이름답게 데이터가 하나하나 위로 쌓이게 됨.

 

var num = 1일때, 스택에 1이라는 값을 제일 아래 칸에 저장함.

 

그 후 var num2 = num을 하게되면 num2는 원래 스택에 있던 1을 가리키는게 아니고,

 

1을 복사해서 그 뒤에 또다른 1을 스택쌓음.

 

그러다보니 num의 값을 2로 바꿔도 맨 아래있던 1이 2로 바뀔뿐이지,

 

그 윗칸에 있는 num2의 값인 1은 그대로 1로 남아있는거임.

 

 

참조값 reference value/type

은 메모리에서 힙 heap이라는 공간에 값을 저장하게 됨.

 

힙에서는 더 많은 양의 데이터를 저장하고 접근에 약간 시간이 걸리며, 데이터가 랜덤하게 자리를 잡고있음.

 

var room = {table: 1}일때, 힙에 {table: 1}이라는 값을 저장함.

 

그리고 room은 어떤 주소(ref)를 통해 {table: 1}이라는 실제 값으로 접근하게 됨.

 

이때 var room2 = room을 하게되면 room2 또한 어떤 주소(ref)를 통해 {table: 1}이라는 값으로 접근하게 됨.

 

둘다 결국 하나의 같은 값으로 접근하게 되는것임.

 

그러다보니 room의 값을 {table: 2}로 바꾸면,

 

둘다 같은 값을 가리키는 원본 값이 변했기때문에 둘다 값이 변하는 것임.

 

 

 

원시값도 reference?

위 설명을 요약하자면 원시값은 a = b를 하는 순간 b가 a의 값을 복사하기때문에 a가 바뀌어도 영향을 안받고,

 

참조값은 a = b를 하는 순간 같은 ref로 값을 공유해서 한쪽이 값을 바꾸면 다른쪽도 바뀐다는 이야기였음.

 

근데 여기서 중요한 개념이 하나 있음.

var a = {num: 1};

function change(val) {
  val.num = 2;
  console.log(val);
}

change(a); // {num: 2}

console.log(a); // {num: 2}

change()라는 함수를 통해 바깥에 있던 a도 {num: 2}로 바뀐다는 흔한 코드임.

 

var a = {num: 1};

function change(val) {
  val = {num: 2};
  console.log(val);
}

change(a); // {num: 2}

console.log(a); // {num: 1}

왜 여기서는 바깥에 있는 변수가 영향을 안받을까

 

방금 전 코드랑 달라진건 한줄밖에 없음.

 

val.num = 2

val = {num: 2}

 

val.num처럼 그 값을 직접 변경(mutate)한다면 원본값도 변경이 되어서 밖에 있는 변수도 바뀐 값을 가짐.

예) val.num = 2

     val.push()

 

val = {num: 2}처럼 그 값을 변경/할당(reassignment)한다면 함수 내에 있는 변수는 아예 다른 ref값을 갖는 다른 변수가 되어버림.

예) val = {num: 2}

     val = null, {}, 195 기타등등

 

밖에 있는 a = {num: 1} 고 ref가 123이라면,

 

안에 있는 a = {num: 2} 고 ref가 456인거임.

 

그렇기때문에 함수 바깥에서 a를 호출하면 123인 a가 나오는것임.

 

 

에이 바깥은 num: 1이고 안은 num: 2라서 당연히 다른거 아님??

 

 

var a = {num: 1};
var b = a;

function change(val) {
  val = {num: 1};
  console.log(val === b);
}

change(a); // false

console.log(a === b); // true

응 아냐

 

일부러 함수에서 값 똑같은걸로 다시 할당(reassignment)을 하고

 

a와 ref가 같은 b랑 대조해봄.

 

함수 안에서 false뜸.

var a = {num: 1};
var b = a;

a = {};

console.log(a); // {}
console.log(b); // {num: 1}

함수의 인자로 들어갈때 어쩌고저쩌고 했다고 함수탓이 아님.

 

위 코드만 봐도 함수따위 안써도 이런 증상이 나타남.

 

mutate vs reassignment 개념임.

 

 

그렇다면 이제 원시값을 보면

var c = 1;

function change() {
  c = 2;
  console.log(c);
};

change(); // 2

console.log(c) // 2

change()라는 함수를 통해 바깥에 있던 c도 값이 2로 바뀐다는 흔한 코드임.

 

var c = 1;

function change(val) {
  val = 2;
  console.log(val);
};

change(c); // 2

console.log(c) // 1

하지만 그런 원시값도 함수의 인자로 들어간다면 이야기가 달라짐.

 

인자로 들어가는순간 ref로 들어감.

 

설명했듯이 object는 애초에 ref로 들어가기때문에 mutate를 했냐, reassignment를 했냐에 따라 원본값이 차이남.

 

그러나 primitive는 애초에 a = 1 이런 할당 방식이기때문에 애초에 reassignment밖에 안됨.

 

바깥에 있는 c = 1은 ref 123인데

 

함수의 인자로 들어가서 값을 할당하는 순간 ref가 456인 또다른 c가 되어버림.

 

그 함수 안에서는 456의 c로써 나타나겠지만 함수 바깥에서는 123인 c가 지배하고 있어서 힘을 못씀.

 

 

 

youtu.be/E-dAnFdq8k8

youtu.be/9ooYYRLdg_g

youtu.be/-hBJz2PPIVE