JavaScript: 원시 타입과 객체 타입

2022년 3월 11일

원시 타입

원시 타입의 값(원시 값)은 변경 불가능한 값(Immutable Value)이다. 즉, 읽기 전용(read-only) 값이다.


원시 값은 변경 불가능한 값이기 때문에 값을 직접 변경할 수 없다. 따라서 변수 값을 변경하기 위해서는 새로운 메모리 공간을 확보하고 재할당할 값을 저장한 후, 변수가 가리키고 있던 메모리 공간의 주소를 변경한다. 값의 이런 특성을 불변성(immutability)이라 한다.


"원시 값은 변경 불가능하다."는 말은 원시 값 자체를 변경할 수 없다는 것이지 변수 값을 변경할 수 없다는 것이 아니다. 변경 불가능하다는 것은 변수가 아니라 값에 대한 진술이다. 변수는 언제든지 재할당을 통해 값을 변경(엄밀히 말하면 교체)할 수 있다. 그렇기 때문에 변수라고 부른다.

값에 의한 전달

다음 코드를 살펴보자.

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

변수에 원시 값을 갖는 변수를 할당하면 할당받은 변수(copy)에는 할당되는 변수(score)의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달이라 한다. 따라서 위 코드에서 변수 copy에는 변수 score의 값 80이 복사되어 전달된다.


위 코드의 과정을 그림을 통해 살펴보자.

pass-by-value

그림을 보면 알 수 있듯이 score 변수와 copy 변수의 값 80서로 다른 메모리 공간에 저장된 별개의 값이다. 따라서 score 변수의 값을 변경해도 copy 변수의 값에는 어떠한 영향도 주지 않는다.


이처럼 값의 의한 전달은 값을 전달하는 것이 아니라 메모리 주소를 전달한다. 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있기 때문에 식별자(변수)는 메모리 주소를 가리키지만 값에 접근할 수 있는 것이다.

객체 타입

객체 타입의 값은 변경 가능한 값(mutable value)다.

객체는 프로퍼티의 개수가 정해져 있지 않으며, 동적으로 추가되고 삭제할 수 있다. 또한 프로퍼티의 값에도 제약이 없다. 따라서 객체는 원시 값과 같이 메모리 공간의 크기를 사전에 정해 둘 수 없다.

var person = {
name: 'Roh',
};

object-assignment

원시 값을 할당한 변수를 참조하면 메모리에 저장되어 있는 원시 값에 접근한다. 하지만 객체를 할당한 변수를 참조하면 메모리에 저장되어 있는 참조 값을 통해 실제 객체에 접근한다. 참조값은 생성된 객체가 실제로 저장된 메모리 공간의 주소다.

객체는 변경 가능한 값이므로 메모리에 저장된 객체를 직접 수정할 수 있다. 위 코드의 객체를 변경해보자.

var person = {
name: 'Roh',
};
person.name = 'Kim';
person.address = 'Seoul';

object-reassignment

이처럼 객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다. 즉, 재할당 없이 프로퍼티를 동적으로 추가, 수정, 삭제가 가능하다.

이때 객체를 할당한 변수에 재할당을 하지 않았으므로 객체를 할당한 변수의 참조 값은 변경되지 않는다.

참조에 의한 전달

객체를 생성하고 관리하는 방식은 복잡하며 비용이 많이 드는 일이다. 만약 객체를 원시 값처럼 이전 값을 복사해서 새로 생성한다면 메모리를 효율적으로 사용하기 어렵고 선능이 나빠진다. 메모리를 효율적으로 사용하고 성능을 향상시키기 위해 객체는 변경 가능한 값으로 설계되어 있다. 객체의 이러한 구조 때문에 부작용이 발생하는데 그것은 여러 개의 식별자가 하나의 객체를 공유할 수 있다는 것이다.

객체의 식별자 공유를 자세히 알아보자.

var person = {
name: 'Roh',
};
// 참조 값을 복사
var copy = person;
console.log(person === copy); // true

객체를 가리키는 원본 변수(person)를 다른 변수(copy)에 할당하면 원본의 참조 값이 복사되어 전달 된다. 이를 참조에 의한 전달이라 한다.


pass-by-reference

원본 person과 사본 copy는 저장된 메모리 주소는 다르지만 동일한 참조 값을 갖는다. 이것은 두 개의 식별자가 하나의 객체를 공유한다는 것을 의미한다. 따라서 원본 또는 사본 중 어느 한쪽에서 객체를 변경하면 서로 영향을 주고받는다.

정리

원시 타입

  • 원시 타입의 값은 변경 불가능한 값이다.
  • 변수에 원시 값을 복사하면 메모리 주소에 저장되어 있는 값이 복사된다. 이를 값에 의한 전달이라 한다.
  • 원본 변수의 값과 복사된 변수의 값은 서로 다른 메모리 공간에 저장되어 있다. 따라서 어느 한 쪽의 값을 변경하더라도 서로 영향을 받지 않는다.

객체 타입

  • 객체 타입의 값은 변경 가능한 값이다.
  • 변수에 객체를 복사하면 메모리 주소에 저장되어 있는 참조 값이 복사된다. 이를 참조에 의한 전달이라 한다.
  • 원본 변수와 복사된 변수는 서로 다른 메모리 주소에 저장되어 있지만 모두 동일한 객체를 가리킨다. 따라서 어느 한 쪽의 값을 변경하면 서로 영향을 받게 된다.

값에 의한 전달참조에 의한 전달은 식별자가 기억하는 메모리 공간에 저장되어 있는 값을 복사해서 전달한다는 면에서 같다. 다만 변수에 저장되어 있는 값이 원시 값이냐 참조 값이냐의 차이만 있을 뿐이다. 따라서 자바스크립트에는 참조에 의한 전달은 존재하지 않고 값에 의한 전달만이 존재한다고 말할 수 있다.


자바스크립트에는 이 같은 동작 방식을 설명하는 정확한 용어가 존재하지 않는다. 이런 이유로 공유에 의한 전달이라고 표현하는 경우도 있다. 하지만 이 용어도 ECMAScript 사양에 정의된 공식적인 용어는 아니며 자바스크립트의 동작 방식을 정확히 설명하지 못한다.


또한, 자바스크립트에는 포인터(pointer)가 존재하지 않기 때문에 포인터가 존재하는 다른 프로그래밍 언어의 "참조에 의한 전달"과 의미가 정확히 일치하지 않는다는 점을 유의해야 한다.


참고

Kihoon
기록하는 프론트엔드 개발자

이전 포스트
[자료구조] 그래프(Graph)의 개념
다음 포스트
[프로그래머스] 최대공약수와 최소공배수 (JavaScript)