[자료구조] 원시타입과 참조타입의 참조변경 과정 (object는 왜 같지 않은가?)

Jeenie·2025년 2월 18일
0

JavaScript

목록 보기
3/3
post-thumbnail

object는 왜 같지 않은가?

const num = 1
const newNum = 1
console.log(num === newNum) // true

const obj = { num: 1 }
const newObj = { num: 1 }
console.log(obj === newObj) // false

numnewNum은 같고, objnewObj는 다르다.

그 이유를 우리는 불변타입의 값을 변경하면 참조가 변경되고,
참조타입의 값을 변경하면 참조가 변경되지 않는다고 외우고 있다.

그런데 왜 그런걸까?
각 변수에 저장된 것은 값이 아닌 메모리 위치이기 때문.
메모리 위치가 같다면 같은 값이고, 메모리 위치가 다르다면 다른 값이다.

간단한 예제로 메모리 할당과정을 알아보자.

원시타입의 경우

원시 타입(number, string, boolean)은 불변(immutable)이므로,
같은 값을 가진 변수를 선언할 때 새로운 메모리를 할당하지 않고 기존 값을 재사용한다.
따라서 값을 변경해도 값은 바뀌지 않고 참조 자체가 변경된다.

const num = 1;
const newnum = 1;
let num2 = 1;

num, newnum, num2은 모두 같은 값과 참조를 가지고 있다.
메모리 할당 과정을 따라가며 참조를 확인해보자.

📌 메모리 할당 과정

1. const num = 1; 실행

숫자 1이 메모리에 저장되고, num은 해당 주소(0x1000)를 참조한다

메모리 주소
0x10001👈 num

2. const newnum = 1; 실행

원시타입의 값은 불변하다.
1이 이미 메모리에 저장되어 있으므로 새로운 공간을 할당하지 않고 기존 주소(0x1000)를 참조한다

메모리 주소
0x10001👈 num, newnum

3. let num2 = 1; 실행

num2도 값 1을 가지므로 새로운 공간을 할당하지 않고 같은 메모리 주소(0x1000)를 참조한다.

메모리 주소
0x10001👈 num, newnum, num2

결과

참조가 모두 동일하다.

값이 변경된다면?

그런데 만약 여기서 num2의 값을 바꾼다면 어떻게 될까?

4. num2 = 2; 실행 (변경 발생!)

num2 = 2

원시 타입은 불변(immutable)이므로, 기존 값을 수정하는 것이 아니라 새로운 메모리 공간을 할당한다 !

2가 새로운 주소(0x1001)에 저장되고, num2는 이제 0x1001을 참조하게 됨.

메모리 주소
0x10001👈 num, newnum (참조 유지)
0x10012👈 num2 (새로운 메모리 공간 할당)

결과

num과 newnum의 참조는 동일하지만,
새로운 공간에 할당된 num2의 참조는 변경되었다.

참조타입의 경우

Object,Array,Function 등의 참조 타입은 가변(mutable) 이다.
참조 타입은 값이 아닌 주소(참조)를 저장하며, 변수 간 복사가 이루어질 때도 값이 아닌 참조가 복사된다.

📌 메모리 할당 과정

const obj1 = { value: 1 };
const obj2 = obj1;
let obj3 = { value: 1 };

1. const obj1 = { value: 1 }; 실행

객체 {value: 1}은 새로운 메모리 공간(예: 0x2000)에 저장되고,
obj1는 해당 객체의 주소(0x2000)를 참조한다.

메모리 주소
0x2000{value: 1}👈 obj1

2. const obj2 = obj1; 실행

obj2는 obj1이 가지고 있는 주소값(0x2000)을 그대로 복사한다.
= 새로운 객체가 생성되지 않고 같은 객체를 참조한다

메모리 주소
0x2000{value: 1}👈 obj1, obj2

3. let obj3 = { value: 1 }; 실행

obj3는 { value: 1 }이라는 새로운 객체를 생성하고, 다른 메모리 주소(예: 0x2001)를 참조한다.
= obj3는 obj1, obj2와 완전히 다른 객체를 참조한다

메모리 주소
0x2000{value: 1}👈 obj1, obj2
0x2001{value: 1}👈 obj3

값이 변경된다면?

여기서 value 값이 변경된다면?

4. obj2.value = { value: 2 }; 실행

obj2.value = 2;

obj1과 obj2는 같은 객체를 참조하고 있으므로, obj1.value도 함께 변경된다.

메모리 주소
0x2000{value: 2}👈 obj1, obj2
0x2001{value: 1}👈 obj3

5. obj3 = { value: 3 }; 실행

let으로 선언했던 obj3에 새로운 값을 할당해보자.

obj3 = { value: 3 };
메모리 주소
0x2000{value: 2}👈 obj1, obj2
0x2001{value: 1}참조되지 않음. GC가 수거해갈 수 있음
0x2002{value: 3}👈 obj3

obj3에 새로운 객체 {value: 3}을 할당하면 새로운 주소(예: 0x2002)를 참조하게 된다.


원시타입의 복사

원시타입은 값만 복사해서 새로운 메모리 공간이 할당된다.

let num1 = 1
메모리 위치
0x12341👈 num1

이때 num2에 num1을 저장하게 되면?

let num1 = 1
let num2 = num1
메모리 위치
0x12341👈 num1
0x12351👈 num2

num1의 값을 복사해서 새로운 메모리 위치에 저장한다.

num1의 값을 가져와 num2에 넣은 것을 알 수 있다.
이 둘은 서로 영향이 있을까?
그렇다면 이제 num2의 값을 변경해보자.

num2 = 2
메모리 위치
0x12341👈 num1
0x12352👈 num2

위치를 저장하지 않고 값만 가져와 새로운 위치에 저장했기 때문에,
num2를 변경해도 num1에는 아무런 영향이 없다.

참조타입의 복사

참조타입(객체, 배열 등)은 값을 복사하는 것이 아니라 주소를 복사한다. 따라서 복사된 두 변수는 같은 객체를 참조하게 된다.

📌 메모리 할당 과정

1. let obj1 = { value: 1 } 실행

let obj1 = { value: 1 }
메모리 위치
0x2000{ value: 1 }👈 obj1

2. obj2 = obj1 실행

let obj2 = obj1

이때 obj2에 obj1을 저장하면

메모리 위치
0x2000{value: 1}👈 obj1, obj2

obj1의 주소를 obj2에 복사하여 두 변수는 동일한 객체를 참조하게 된다.

값이 변경된다면?

그럼 여기서 obj2의 값을 변경하면 어떻게 될까?

3. obj2.value = 2 실행

obj2.value = 2
메모리 위치
0x2000{value: 2}👈 obj1, obj2

obj2를 변경하면 obj1도 영향을 받는다 !
왜냐하면 두 변수는 같은 객체를 참조하고 있기 때문이다.

4. obj1 = {value: 3} 실행

obj1 = { value: 3 }

이제 obj1에 새로운 객체를 할당하면, obj2는 여전히 기존 객체를 참조하고 있다.

메모리 위치
0x2001{value: 3}👈 obj1
0x2000{value: 2}👈 obj2

새로운 객체가 할당되었기 때문에 obj1은 새로운 메모리 주소를 참조하게 된다.

profile
Web Front-end developer

0개의 댓글

관련 채용 정보