[JS] 11장 원시값과 객체의 비교 | 모던자바스크립트 Deep Dive

sehannnnnnn·2021년 7월 15일
0

JavaScript DeepDive

목록 보기
1/7
post-thumbnail

원시 타입? 객체 타입?

  • 원시타입 : string, number, boolean 등
    1) 변경이 불가능한 값 (읽기전용)
    2) 메모리에 실제 값이 저장됨
    3) 다른 변수에 할당 할 시, 원시 값이 복사되어 전달
  • 객체 타입 : object
    1) 변경이 가능한 값
    2) 메모리에는 참조 값이 저장됨
    3) 다른 변수에 할당 시, 원본의 참조 값이 복사되어 전달

"값의 변경이 불가능하다" 는 무슨말잉교?

변경이 불가능 하다는 것은 '변수'의 변경이 아닌 '값'에 대한 변경이 불가하다는 진술이다.

위 말을 이해하기 위해서는 JavaScript의 변수 재할당 매커니즘을 이해해야한다!

JavaScript에서는 변수가 새 값으로 재할당 될 때 메모리공간을 새로 생성하여 변수이름과 변수값을 지정한다. 그 과정에서 기존에 변수가 머물렀던 메모리공간 속 변수 값은 변경되거나 삭제되지 않는다. (오랫동안 사용하지 않으면 가비지컬렉터가 자동으로 삭제한다.)

위 설명 같이 원시값은 재할당은 가능하지만, 변수로 저장되있는 메모리공간에 있는 직접 접근하여 변경하는 것은 불가능하다. 이러한 특성을 '값의 변경이 불가능하다'고 말하며, 이를 불변성(immutability)라고 한다.
불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 수 있는 방법이 없다!


위 개념을 잘 이해해야 JavaScript의 변수에 관련하여 헷갈리는 부분이 줄어든다.

문자열과 불변성

  • C와 같은 다른 언어의 경우
    문자열에 경우 하나의 문자당 2바이트가 필요하다. 숫자 데이터는 모든 수 동일하게 8바이트가 필요한 반면, 10개의 문자로 이루어진 문자열은 20바이트가 필요하다.
  • JavaScript의 경우
    문자열을 변경 불가능한 원시타입으로 제공한다. (장점!)
var str = 'hello';
str = 'world'; // 다른 변수 타입과 마찬가지로 재할당과정이 이루어짐!

str 변수의 내부 값이 변환되는 것이 아닌 값을 담고 있는 주소의 값이 변경된다. str변수가 기존에 'Hello'를 가르키고 있다가 'world'라는 새 메모리 주소를 가르킨다.

결국, 문자열의 한 문자를 변경하더라도 본 데이터 값은 변환되지 않는다.
따라서, 예기치 못한 변경으로 자유로우며, 데이터의 신뢰성을 보장한다.

 var str = 'string';
 str[0] = 'S'; //에러를 나타내지는 않음
 console.log(str); //'string' 내부 문자열이 수정되지 않았다! 

값에 의한 전달

var score = 80;
var copy = score; 

console.log(score);  //80
console.log(copy);  //80

score = 100; 

console.log(score); //100
console.log(copy); //80? 100?

score 변수에 숫자 80을 할당하고 copy변수에 score를 할당했다. 그 후, score변수에 새로운 숫자값 100을 재할당하면 copy값이 100이 될까, 80이 될까?

코드에 따라 이루어지는 동작은 다음과 같다.

1. 변수 score에 할당된 80이라는 원시 값이 복사되어 변수 copy에 할당(복사되어 전달)
2. 변수 copy의 값은 80이 됨!
3. 변수 score에 재할당(새로운 메모리 공간에 100을 할당하고 score가 100의 주소를 가르킴)
4. 변수 copy는 그대로 80, 변수 score는 100이 됨. 

정리하자면, score변수와 copy변수는 각각 다른 메모리값에 저장된 별개의 값이기 때문에, score에 어떠한 작업을 하여도 이미 선언된, 할당된 copy변수엔 어떤 영향도 주지 않는다.


객체

객체는 원시값과 다르게 변경이 가능하다!
프로퍼티의 개수 제한이 없고, 동적으로 추가, 삭제할 수 있다.


c++, java 사전에 정의된 클래스 기반 객체생성, 객체 생성 이후 프로퍼티 삭제, 추가 불가
JavaScript 클래스 없이 객체 생성, 생성 이후 동적으로 프로퍼티 삭제 추가, 가능! (성능에서는 유리하나, 객체 생성, 접근에 비용이 더 많이듬😕)

var x = {name : 'Lee'};

객체의 프로퍼티(값)과 변수식별자(x)는 각각 다른 메모리에 저장되며 x의 공간에는 객체 프로퍼티를 가르키는 주소가 저장되있다. 프로퍼티 메모리에는 {name:'Lee'}가 저장되있어 식별자가 프로퍼티를 참조하는 방식으로 설계되었다. (이는 원시타입과 다름!)

why?
객체 생성 자체의 생성 관리 방식이 복잡하고 비용이 많이 들기 때문에, 효율적으로 메모리를 사용하기 위해, 객체를 원시값처럼 복사, 재할당하는 과정에 비용을 절약하여 성능을 높히기 위해 변경가능한 값으로 설계되었다.

단점: 근데 이거 때매 여러개의 식별자(변수명)이 하나의 객체를 공유하게 된다..

참조에 의한 전달

var person = {
   name : 'Lee'
   };
  
var copy = person;

console.log(copy === person); //true

//프로퍼티 변경, 추가
copy.name = 'kim';
person.address = 'seoul';

console.log(person); //{name: 'kim', address : 'seoul'}

위 코드에 경우, 변수 person이 가르키고있던 객체{name:'Lee'}에 대한 주소값을 변수 copy에 복사하여 전달한다. 객체{name:'Lee'}에 값은 복사되지 않고 그대로 있으며 person과 copy둘다 모두 객체{name:'Lee'}에 주소를 갖고 있기 때문에 둘은 같은 객체를 '공유'했다라 할 수 있다.

따라서, 원본 또는 사본에서 객체를 변경(프로퍼티 추가, 삭제)하면 서로 영향을 주고 받는다.


Quiz

var person1 = {name: 'Lee'};
var person2 = {name: 'Lee'};

console.log(person1 === person2); // 1번
console.log(person1.name === person2.name); // 2번

=== 연산자
객체는 참조값 비교, 원시값 변수는 원시값 비교

1번 : false
객체는 선언 될 때마다 새로운 객체를 생성한다. person1과 person2는 같은 구성이지만 엄연히 다른 별개의 객체이며 다른 주소값을 갖고 있다. 즉, person1과 person2의 참조값은 전혀 다른 값이다!

2번 : true
person1.name과 person2.name은 모두 값을 반환하는 표현식이다. 이 둘은 원시값 'Lee'로 평가되어 true이다.

profile
FE 개발자 준비생 블로그 🪐

0개의 댓글