본문 바로가기
JavaScript Study

JavaScript - #12. 원시값과 객체 (1)

by KMS_99 2023. 8. 28.

자바스크립트에는 총 7개의 데이터 타입이 있으며 이는 크게 원시 타입과 객체 타입으로 나누어진다.

  원시 타입 객체 타입
데이터 타입 숫자, 문자열, 불리언, null, undefined, 심벌 객체
특징 - 변경 불가능한 값
- 변수에 실제 값 저장
- 변수에 원시값을 갖는 변수 할당 시 원시값이 복사되어 할당 / 값에 의한 전달
- 변경 가능한 값
- 변수에 참조 값 저장
- 변수에 참조값을 갖는 변수 할당 시 참조값이 복사되어 할당 / 참조에 의한 전달

원시 타입과 객체 타입을 구분하는 특징은 위 표에 명시된 내용이며, 각각의 내용을 자세히 알아보자.

 

1. 원시 타입

 

- 변경 불가능한 값

원시타입의 값은 변경 불가능한 값이다. 최초 생성된 원시값은 읽기 전용으로 변경이 불가능하다.

변수는 값을 저장하기 위해 확보한 메모리 공간을 의미하며, 그 공간을 식별하기 위한 것이다. 

값은 표현식으로 평가 된 결과이다.

 

원시값이 변경 불가능하다고 했는데 변수는 재할당이 가능해서 변경이 가능한 것이아닌가? 라고 생각이 들 것이다.

 

여기서 이야기하는 변경 불가능한 값은 원시 값 그 자체 이고, 변수 값은 언제나 재할당이 가능하다. (const 제외)

이 차이를 분명히 알아야한다.

 

원시 값은 변경 불가능 하기 때문에 데이터의 신뢰성을 보장한다.

 

위에서 이야기 한 것 처럼 변수값은 재할당이 가능하다. 그렇다면 내부적으로는 어떤 방식으로 재할당이 이루어질까?

변수에 원시값을 재 할당하면, 이미 있던 원시값이 변화하는 것이 아닌 새로운 공간을 확보하고 재할당 한 원시값을 저장한 후 변수는 새로운 공간에 재할당된 원시값을 가리키게 된다.

따라서 이때 변수가 참조하고 있던 공간의 주소가 변경된다.

위 그림에서 진행되는 과정을 알아보자.

먼저 let score; 문를 통해 변수가 선언되었을 때 메모리에서는 최초 초기화가 undefined 타입으로 되기 때문에 score 변수의 값인 undefined를 담을 메모리 공간이 확보가 되며 저장이 된다.

다음 score=80; 문이 실행되며, score 변수의 값가 재할당이 되게 된다.

메모리에서는 기존에 참조했던 주소에 있는 undefined가 변경되는 것이 아니라 새로운 메모리 공간이 할당이 되며, 해당 공간에 80이라는 값이 들어가게 된다. 이때부터 score 변수는 참조를 80이 들어있는 공간에 하게 된다.

당음 score=90; 문이 실행되며 방금 진행되었던 매커니즘과 같이 새로운 공간에 90이라는 원시값이 들어가며, 이후 변수 score는 90의 값을 가지고 있는 메모리 주소을 참조하게된다.

 

이와같이 변수의 값이 변화 할 때 새로운 공간이 할당되며, 기존값을 나타내는 공간에는 영향을 미치지 않는 이유는 원시값은 변경이 불가능하기 때문이다. 이러한 특성을 불변성이라고 한다. 

불변성을 가지고 있는 원시 값을 할당한 변수는 재할당 외에는 변수값을 변경할 수 있는 방법이 없다. 

 

- 문자열과 불변성

원시값을 저장하려면, 먼저 데이터 타입에 따른 메모리 공간의 크기가 결정되어야한다.

이를 위해서 원시 타입 별로 기본적으로 필요한 공간의 크기가 정해져있다.

 

그중에서도 문자열은 다른 원시값과는 다른 독특한 특징이 있다. 

1개의 문자는 2바이트의 메모리공간에 저장이되며, 문자열은 문자의 집합이다.

따라서 문자의 개수에 따라서 가변적인 메모리 공간이 할당되어야 할 것이다.

자바스크립트의 장점중 하나는 이 문자열의 크기를 가변적으로 변경할 수 있으며, 문자열 자체가 원시타입인 것이다.

따라서 문자열 역시 불변성을 가지는 원시타입이다.

문자열이 갖는 추가적인 특징은 유사배열이라는 것이다.

let str = 'string';

//문자열은 유사배열의 특징을 가져 인덱스로 접근가능, for 반복문으로 순회도 가능
console.log(str[0]); // 's'

//문자열은 객체처럼 동작
console.log(str.length); // 6
console.log(str.toUpperCase()); //'STRING'

문자열은 원시 타입이지만, 유사배열객체로 배열처럼 인덱스로 프로퍼티값에 접근이 가능하며 length 프로퍼티를 갖는다. 이러한 것이 가능한 이유는 문자열을 객체처럼 사용할 때 값을 감싸는 래퍼객체로 자동 변환이 되기 때문이다. 자세한건 추후 공부해보자.

그렇다면 이러한 유사배열 특징을 이용하여 값의 일부를 변경하면 어떻게 될까?

let str = 'string';

str[0]= 'k';

console.log(str); //'string'

객체처럼 동작하더라도 문자열은 원시 타입이기에 값의 불변성을 가지고 있다.

따라서 값은 변화하지 않는다. 하지만 오류가 발생하지 않으니 주의하자.

 

- 값에 의한 전달

let score = 80;
let copy = score; // 변수 식별자로 초기화

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

score = 100;

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

위와 같이 80의 값을 가진 변수 score 자체를 새로운 변수 copy를 초기화 하는데 값으로 할당하자.

그렇다면 메모리에서는 어떻게 작용할까?

copy에 score 변수가 할당된다고 해서 기존 score변수의 값인 80을 참조하는 것이 아니라. score가 가지고 있는 80이라는 값을 복사해서 새로운 공간에 그 값을 할당하는 것이다. 따라서 참조하는 주소 역시 새로운 공간에 있는 80이 된다.

이를 값의 의한 전달이라고 한다.

주의해야할 점은 이것이 정답이 아닐 수 있다는 것이다.

자바스크립트 엔진에서 내부동작은 위 그림처럼 이루어지지 않을 수 있기 때문에 정답이라고 생각하면 안된다.

새로운 변수에 기존변수를 할당했을 때 두 변수가 참조하는 주소가 같을 수 있으며, 이후 재할당이 이루어졌을 때 새로운 메모리 공간을 확보하여 할당될 수도 있다.

 

이는 자바스크립트 엔진마다 상이하기 때문에 정확하게 정답이라고 말할 수 없다.

 

결론은 원시값을 가진 기존 변수 자체를 새로운 변수에 할당한다고 해서 기존 원시값에는 아무 영항을 미치지 않는다는 것이다.