원시 타입 | 객체 타입 | |
---|---|---|
변수에 할당하면? | 실제 값이 저장됨 | 참조값이 저장됨 |
각 타입의 값 | 원시값 : 변경 불가능한 값 | 객체 타입의 값 : 변경 가능한 값 |
원시값을 갖는 변수를 다른 변수에 할당하면? | 원시값이 복사됨. | 참조값이 복사됨. |
※ 사전지식
- 변수명(식별자) : 변수 값이 저장되는 ‘메모리 공간’을 지칭하기 위해 붙인 이름이고
- 변수의 값은 : 메모리에 저장된 ‘데이터 자체’이다.
let score = 80;
< 코드 생성과정 >
1)새로운 메모리 주소에 공간을 만들고
2) score식별자는 그 주소를 가르키게 된다.
3)메모리 공간에 80이라는 “값”을 할당한다.
식별자(score)는 “값(80)"이 아니라, 값이 담긴 “메모리 주소"를 기억하고 있는 것임.
원시값은 불변성을 띈다. 때문에 재할당을 통해 값을 교체할 수 있음.
메모리에 저장되있는 "원시값"은 변경할 수 없지만, 재할당을 통해 새로운 메모리 공간을 확보하고 그곳에 재할당한 값을 저장한 후, 변수 식별자가 참조하던 "메모리 공간의 주소가 변경"되어 재할당 되는 것임.
(원시값이 변경 불가능한 값이기 때문에 변수가 참조하던 메모리 공간의 주소가 변경되는 것!)
var num;
num = 80;
num = 100;
let str = "hello";
str[0] = "j";
console.log(str) // "hello"
let score = 80;
let copy = score;
// [p1]
console.log(score); // 80
console.log(copy); // 80
score = 100;
// [p2]
console.log(score); // 100
console.log(copy); // 80 !!
: copy변수에 원시값을 갖는 변수인 score을 할당하면, copy에는 score의 “원시값”이 복사되어 전달됨.
: score변수와 copy변수는 같은 값(80)을 갖지만, 다른 메모리 공간에 저장된 별개의 값이다!
때문에 score값을 재할당해도 copy변수의 값에는 영향을 주지 않는 것임!
let person = {name:"Lee"};
< 코드 생성과정 >
1) 메모리 주소(0x001)에 공간을 만들어지고
2) 변수 식별자는 그 메모리 주소(0x001)를 가르키게 된다.
3) 다른 메모리 공간(0x002)에 실제 객체값이 담긴다.
4) 메모리 공간(0x001)에 저장된 참조값이 이 실제 객체를 가르키게 된다.
< 객체값을 참조하는 과정 >
원시값은 변경 불가능한 값이므로 재할당을 통해 새로운 메모리에 원시값을 새로 생성해야 했지만,
참조값은 변경 가능한 값이므로 기존 메모리에 있는 객체를 직접 수정할 수 있다.
let person = {name:"Lee"};
person.name = "Kim";
person.adress = "Seuol";
let person = {name:"Lee"};
let copy = person; // 얕은 복사, person의 참조값을 복사한 것임.
원시타입은 원시”값”자체가 복사되어 전달되지만, 참조타입은 “참조값(reference)”가 복사되어 전달된다.
때문에 person과 copy는 메모리 주소는 다르지만, 동일한 참조값을 공유하고 있게 된다.
따라서 person과 copy 중 한쪽에서 객체를 수정하면 서로 영향을 받게 된다.
let obj1 = {a : 1};
let obj2 = {a : 1};
console.log(obj1 === obj2); // false
console.log(obj1.a === obj2.a); // true
얕은 복사와 깊은 복사로 생성된 원본과 복사본은 참조 값이 다른 별개의 객체다.
하지만 중첩 객체를 복사하는 경우
const obj = {x:{y:1}};
// 얕은 복사
const c1 = {...obj}; // {y:1}객체는 원본과 사본이 같은 값을 공유하게 된다.
// 깊은 복사
const c2 = JSON.parse(JSON.stringify(obj));