원시 값: 원시 타입의 값, 변경 불가능한 값이다.
원시 값을 변수에 할당하면 변수에는 실제 값이 저장된다.
원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달이라 한다.
객체: 객체(참조) 타입의 값, 변경 가능한 값.
객체를 변수에 할당하면 변수에는 참조 값(메모리를 가리키는 주소값)이 저장된다.
객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다. 이를 참조에 의한 전달이라 한다.
상수는 재할당이 금지된 변수를 말한다. 따라서 변경 불가능한 값인 원시 값과는 별개의 개념이다.
// const 키워드를 통해 선언한 변수는 재할당이 금지된다. 여기서 할당한 원시 값({})은 어떤 일이 있어도 불변한다.
const o = {};
// 하지만 선언한 원시 값에 할당된 객체는 변경할 수 있다.
o.a = 1;
console.log(o); // {a: 1}
ECMAScript 사양에 의하면, 숫자 값은 8바이트(byte), 문자 값은 2바이트(byte)를 한 메모리 공간으로 차지하고 있다. 그렇기 때문에 숫자값은 1도, 100000도 동일한 8바이트라는 메모리 공간에 저장되지만, 문자열의 경우는 그 공간이 잘게 쪼개져있다.
자바스크립트는 개발자의 편의를 위해 원시 타입인 문자열 타입을 제공한다. 이는 문자열이 생성된 이후에는 변경이 불가능하다는 것을 의미한다.
var str = 'Hello';
// 해당 재 선언된 str의 'world'는 다른 메모리 공간에 있어,
//참조 시에 해당 메모리 주소를 참조만 하게 된다. 원본인 'Hello'의 메모리 공간은 그대로 남아있게 된다.
str = 'world';
// 문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용하여 각 문자에 접근할 수 있다.
// 하지만 문자열은 원시값이기 때문에 변경할 수 없다. 에러는 발생하지 않지만, 값은 그대로이다.
str[0] = 'W';
console.log(str); // world
var score = 80;
var copy = score; // 여기서는 score의 메모리 주소값이 아닌, 값만 복사하여 새로이 할당한다.
console.log(score); // 80;
console.log(copy); // 80;
score = 100;
console.log(score); // 100;
console.log(copy); // 80;
비교적 적은 메모리를 사용하는 원시 값에 비해, 객체는 많은 메모리를 사용하게 될 수도 있다. 이를 위해 객체는 비교적 다른 방식으로 동작하도록 설계되어 있다.
//원시 값을 할당한 변수는 원시 값 자체를 값으로 갖지만,
//객체를 할당한 변수가 기억하는 메모리 주소를 통해 메모리 공간에 접근하면 참조 값에 접근할 수 있다.
// person이라는 원시 값을 할당한다.
var person = {
name: 'Lee'
};
// person 변수에 저장되어 있는 참조 값으로 실제 객체에 접근한다.
// person 변수는 객체 {name: 'Lee'}를 가리키고 있는 것이다.
console.log(person); // {name: 'Lee'}
// 객체는 원시값이 아니기 때문에 갱신하고, 삭제할 수도 있다.
person.name = 'Kim';
console.log(person); // {name: "Kim"}
이렇게 객체 값만 참조를 하기 때문에, 다른 원시값에서 참조할 경우, 같은 메모리 주소를 참조하게 된다는 이슈가 생긴다.
const o = { x: { y: 1 } };
// 얕은 복사(원본과의 가장 가까이 있는 한단계의 참조가 공유된다.)
const c1 = { ...o }; // 전개 연산자
console.log(c1 === 0); // false
console.log(c1.x === o.x); // true
o.x.y = 3;
console.log(o.x.y); // 3
console.log(c1.x.y); // 3
o.x = 2;
console.log(o.x); // 2
console.log(c1.x); // { y: 3 }
// 깊은 복사(원본과의 참조가 완전히 끊어진 객체)
const obj = {
a: 1,
b: {
c: 2,
},
};
const copiedObj = JSON.parse(JSON.stringify(obj));
copiedObj.b.c = 3
obj.b.c === copiedObj.b.c //false