728x90
반응형
SMALL

원시값 vs 객체: 메모리 저장 방식의 차이
변수에 값을 할당할 때 원시값과 객체는 메모리에 저장되는 방식이 다릅니다.
원시값 - 값 자체를 저장
let a = 10;
let b = a;
환경 레코드 메모리
┌───┬────────┐
│ a │ 0x1000 │ ──→ [0x1000]: 10
│ b │ 0x2000 │ ──→ [0x2000]: 10 (값 복사)
└───┴────────┘
특징:
- 변수마다 독립적인 메모리 공간
- 값 자체를 직접 저장
- 복사하면 새 메모리에 값 복사
재할당 시
a = 20;
환경 레코드 메모리
┌───┬────────┐
│ a │ 0x3000 │ ──→ [0x1000]: 10 (b가 사용 중)
│ b │ 0x2000 │ ──→ [0x2000]: 10 (그대로)
└───┴────────┘ [0x3000]: 20 (새로 생성)
console.log(a); // 20
console.log(b); // 10 (독립적)
- 새 메모리 생성 후 재바인딩
- 각 변수는 독립적
객체 - 참조값(주소)을 저장
let obj1 = { value: 1 };
환경 레코드 스택 힙
┌──────┬─────┐
│ obj1 │ 0x1 │ ─→ [0x1]: 0x5000 ─→ [0x5000]: { value: 1 }
└──────┴─────┘ (참조 저장) (실제 객체)
특징:
- 2단계 메모리 사용 (스택 + 힙)
- 스택: 힙 메모리 주소(참조값) 저장
- 힙: 실제 객체 저장
객체 복사 - 참조 공유
let obj1 = { value: 1 };
let obj2 = obj1; // 참조값 복사
환경 레코드 스택 힙
┌──────┬─────┐
│ obj1 │ 0x1 │ ─→ [0x1]: 0x5000 ─┐
│ obj2 │ 0x2 │ ─→ [0x2]: 0x5000 ─┴→ [0x5000]: { value: 1 }
└──────┴─────┘ (같은 참조) (같은 객체)
- obj1, obj2는 다른 스택 메모리 사용
- 하지만 같은 힙 주소 저장
- 같은 객체를 참조
객체 수정 - 내용만 변경
obj1.value = 2;
환경 레코드 스택 힙
┌──────┬─────┐
│ obj1 │ 0x1 │ ─→ [0x1]: 0x5000 ─┐
│ obj2 │ 0x2 │ ─→ [0x2]: 0x5000 ─┴→ [0x5000]: { value: 2 }
└──────┴─────┘ (내용만 수정)
console.log(obj1.value); // 2
console.log(obj2.value); // 2 (같은 객체 참조)
- 힙 주소는 그대로 (0x5000)
- 객체 내용만 변경
- 모든 참조에 영향
비교 예시
// 원시값 - 값 복사
let a = 10;
let b = a;
a = 20;
console.log(b); // 10 (독립적)
// 객체 - 참조 복사
let obj1 = { value: 10 };
let obj2 = obj1;
obj1.value = 20;
console.log(obj2.value); // 20 (같은 객체)
메모리 사용 차이
원시값: 1단계
변수 → 메모리 → 값
객체: 2단계
변수 → 스택 → 힙 → 실제 객체
객체는 메모리를 한 번 더 사용합니다:
- 스택: 참조값 저장 (작은 크기)
- 힙: 실제 객체 저장 (큰 크기 가능)
핵심 정리
| 원시값 | 객체 | |
| 저장 | 값 직접 저장 | 참조(주소) 저장 |
| 복사 | 값 복사 (독립적) | 참조 복사 (공유) |
| 변경 | 새 메모리 + 재바인딩 | 같은 메모리, 내용만 수정 |
| 메모리 | 1단계 (직접) | 2단계 (스택 + 힙) |
// 원시값: 값으로 평가
let x = 10; // x → 10
// 객체: 참조로 평가
let obj = { value: 1 }; // obj → 주소 → { value: 1 }
기억하기:
- 원시값: 값 자체를 저장 📦
- 객체: 주소(참조)를 저장 🏠📍
객체 재할당? - 새 객체, 새 주소
let obj = { value: 1 };
환경 레코드 스택 힙
┌─────┬─────┐
│ obj │ 0x1 │ ─→ [0x1]: 0x5000 ─→ [0x5000]: { value: 1 }
└─────┴─────┘
// 새 객체로 재할당
obj = { value: 2 };
환경 레코드 스택 힙
┌─────┬─────┐
│ obj │ 0x1 │ ─→ [0x1]: 0x6000 ─→ [0x5000]: { value: 1 } (GC 대상)
└─────┴─────┘ (새 참조) [0x6000]: { value: 2 } (새 객체)
동작:
- 힙에 새 객체 생성 (0x6000)
- 스택의 참조값을 새 주소로 변경
- 기존 객체 (0x5000)는 GC 대상
프로퍼티 수정 vs 객체 재할당
프로퍼티 수정 - 같은 주소
let obj = { value: 1 };
obj.value = 2; // 같은 객체, 내용만 수정
환경 레코드 스택 힙
┌─────┬─────┐
│ obj │ 0x1 │ ─→ [0x1]: 0x5000 ─→ [0x5000]: { value: 2 }
└─────┴─────┘ (주소 그대로) (내용 변경)
객체 재할당 - 새 주소
let obj = { value: 1 };
obj = { value: 2 }; // 새 객체
환경 레코드 스택 힙
┌─────┬─────┐
│ obj │ 0x1 │ ─→ [0x1]: 0x6000 ─→ [0x5000]: { value: 1 } (GC)
└─────┴─────┘ (주소 변경) [0x6000]: { value: 2 } (새 객체)
참조 공유 시 차이
let obj1 = { value: 1 };
let obj2 = obj1;
// 1. 프로퍼티 수정
obj1.value = 2;
console.log(obj2.value); // 2 (같은 객체)
// 2. 객체 재할당
obj1 = { value: 3 };
console.log(obj2.value); // 2 (다른 객체)
그림으로 보면:
프로퍼티 수정 후:
obj1 → [0x1]: 0x5000 ─┐
obj2 → [0x2]: 0x5000 ─┴→ [0x5000]: { value: 2 }
(같은 객체, 내용만 변경)
객체 재할당 후:
obj1 → [0x1]: 0x6000 ──→ [0x6000]: { value: 3 } (새 객체)
obj2 → [0x2]: 0x5000 ──→ [0x5000]: { value: 2 } (기존 객체)
정리
프로퍼티 수정 (obj.value = 2):
- 힙 주소 그대로
- 객체 내용만 변경
- 모든 참조에 영향
객체 재할당 (obj = { ... }):
- 힙에 새 객체 생성
- 스택의 참조값 변경
- 다른 참조에 영향 없음
// 수정
obj.value = 2; // 같은 메모리, 내용 변경
// 재할당
obj = { value: 2 }; // 새 메모리, 주소 변경
말씀하신 대로, 재할당하면 힙에 새 객체 생성 + 새 메모리 주소로 재바인딩입니다! 🎯
728x90
반응형
LIST
'javascript' 카테고리의 다른 글
| JavaScript 메모리 이해하기: 값 전달 vs 참조 전달 (0) | 2026.01.25 |
|---|---|
| 해시 테이블과 JavaScript 객체 (0) | 2026.01.25 |
| super vs 프로토타입 체인 (0) | 2026.01.25 |
| 바인딩 vs 할당 vs 참조 (0) | 2026.01.25 |
| null === null, undefined === undefined, NaN === NaN (0) | 2026.01.24 |
댓글