[DEEP DIVE] 11. 원시 vs 객체
원시 vs 객체
원시 : 원시 값을 변수에 할당하면 변수가 가르키게 되는 메모리의 주소에 실제 값이 저장된다. 이 변수를 다른 변수에 할당하면, 원시 값이 복사되어 전달된다
객체 : 객체를 변수에 할당하면 변수가 가르키게 되는 메모리의 주소에 참조 값(객체를 저장하고 있는 메모리의 첫번째 주소)이 저장된다. 이 변수를 다른 변수에 할당하면, 참조 값이 복사되어 전달된다
1. 원시 값
원시 값은 변경 불가능한 값이다. 즉, 한번 생성된 원시 값은 읽기 전용으로써 변경할 수가 없다.
🧐 '값을 변경할 수 없다.' 의 구체적인 의미가 무엇일까?
var x = 10
x = 20
console.log(x) // 20
변수는 메모리 공간에서 주소를 식별하는 식별자이다.
x는 10이 저장된 메모리의 주소를 기억하고, 이 주소를 식별한다
10 은 변수 x 에 저장된 원시 값이다.
여기서 변경 불가능 하다는 것은 10 인 원시 값을 변경할 수 없다는 것을 의미한다.
메모리에 10이 저장되면 그 메모리에 저장된 값을 변경할 수 없다는 것!!
🧐 원시 값을 변경할 수 없다고 했는데 왜 콘솔에는 20이 찍히나요??
원시 값을 변경하는 것이 아니라 변수가 가르키고 있는 메모리 주소를 변경하는 것이기 때문이다~
20을 저장할 새로운 메모리 공간을 생성하고, 변수가 가르키고 있는 메모리 상의 주소를 변경한다.
원시 값은 메모리 상에서 불변성을 가진다!
원시 값을 할당해준 변수 값을 변경할 수 있는 유일한 방법이 재할당이다. 이 이외의 방법은 없다.
📌 문자열과 불변성
js 에서 문자열도 불변성을 가지는 원시 값이며, 유사 배열 객체이다.
1. 배열처럼 인덱스로 값에 접근할 수 있고,
2. length 프로퍼티를 갖는다.
var str = 'hello';
str = 'world';
console.log(str) // world
str[0] = 'a'
console.log(str) // world
js 에서 하나의 문자는 2바이트 이기 때문에, 'world' 는 메모리 상에서 10 바이트를 차지하고 있을 것이다.
인덱스로 하나의 문자에 접근해서 원시값인 문자열을 변경할 수 없다.
'aorld' 로 변경 하려고 해도 'world' 로 유지된다.
📌 값에 의한 전달
var x = 10;
var y = x;
console.log(x === y); // true
console.log(y); // 10
x += 10;
console.log(x); // 20
console.log(y); // 10
변수 y 에 변수 x 를 할당하면 변수 x 가 가르키고 있는 메모리의 주소에 저장된 값인 10이 복사되어 전달된다
x, y 가 가르키는 메모리 상의 주소가 다르다!!
따라서 x 의 값을 변경해도 y 의 값은 전혀 영향을 받지 않는다.
두 변수는 별개의 메모리 공간에 저장되기 때문에 원시 값만 일치하고 주소는 다르기 때문에 서로 간섭할 수 없다.
2. 객체
js 는 자바, C++ 같은 객체지향 프로그래밍 언어와 다르게 객체를 생성하기 이전에 클래스를 정의해 줄 필요가 없다.
객체 리터럴을 통해서 객체를 생성할 수 있으며 동적으로 프로퍼티, 메서드를 추가할 수 있다는 장점이 있다.
객체 타입의 값은, 변경 가능한 값이다
객체를 할당해준 변수는 원시 값을 할당해준 변수와 마찬가지로 메모리 주소를 기억하지만, 참조 값을 저장한다
🧐 참조 값?
숫자, 문자와 같은 원시 값이 아닌 객체의 시작 메모리 주소를 의미한다.
객체를 할당한 변수는 이 시작 메모리 주소를 저장하고 있다.
따라서, 객체가 저장된 메모리 주소에 접근할 수 있게 된다.
객체가 저장되어 있는 변수를 참조하면, 그 변수에 저장되어 있는 메모리 주소에 저장된 값은 객체의 주소이다.
이 참조값을 통해서 실제 객체에 접근할 수 있는 것이다.
변수는 객체에 저장된 프로퍼티, 메서드 자체를 모두 기억하고 있는 것이 아니라, 변수는 객체를 가르키고 있다 라고 생각하면 편할 듯 싶다.
📌 객체 변경하기
var user = {
name : 'woong';
}
// 갱신
user.name = 'choi';
// 추가
user.age = 24;
user.address = 'busan';
🧐 왜 원시 값은 변경 불가능 하고, 객체 값은 변경이 가능한가?
객체를 변경할 때마다 원시 값이 저장된 변수를 재할당 하는 것처럼, 값을 복사해서 새롭게 재할당 해준다면 객체 값도 불변성을 유지할 수 있는 장점이 있지만 객체 값에 저장된 프로퍼티와 메서드 수가 일정하지 않고 객체 값에 객체가 또 추가될 수 있기 때문에 메모리를 효율적으로 소비하기 힘들다는 단점이 있다.
프로그램의 크기가 커지면, 자연스럽게 객체 값도 커지게 될텐데 원시 값처럼 복사를 통해 재할당을 해준다면 메모리를 굉장히 비효율적으로 사용하게 되고 성능도 보장할 수 없다.
메모리를 효율적으로 사용하기 위해서 복사를 통해 생성하는 비용을 절약하는 대신 객체 값을 변경 가능하도록 설정한 것이다!
참조값을 할당해주기 때문에, 여러 식별자가 하나의 객체를 공유 하는 것이 가능하다!
그러나 여러 식별자가 공유할 수 있는 만큼, 부작용이 발생하기 쉽다. 조심해야 한다
📌 참조에 의한 전달
var person = {
id : 'woong',
age : 24,
}
// 객체가 저장된 메모리상의 주소를 가지고 있는 변수 person 을 copy_person 에 복사
var copy_person = person;
console.log(copy_person === person); // true
// 값 갱신
copy_person.age = 4;
console.log(person.age, copy_person.age); // 4 4
// 프로퍼티 추가
copy_person.address = 'busan';
console.log(person, copy_person); // {id: 'woong', age: 4, address: 'busan'} , {id: 'woong', age: 4, address: 'busan'}
🐱 한줄 요약
값에 의한 전달 : 원시 값 복사, 별개의 메모리 주소이기 때문에 공유 불가능
참조에 의한 전달 : 객체의 시작 주소를 저장하고 있는 변수 값 할당, 여러 식별자가 모두 같은 메모리 주소를 가르키고 있기 때문에 공유 가능