[코어 자바스크립트] 💍 불변값 vs 가변값 vs 변수 vs 상수

  • 불변값과 상수는 같은 개념이 아님

변수와 상수

  • 변수와 상수를 구분하는 성질은 “변경 가능성”
  • 변수와 상수를 구분 짓는 “변경 가능성”의 대상은 변수 영역 메모리
  • 바꿀 수 있으면 변수
  • 바꿀 수 없으면 상수
  • 한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건

불변값

  • 불변성 여부를 구분할 때의 “변경 가능성”의 대상은 데이터 영역 메모리
  • 기본형 데이터인 숫자, 문자열, boolean, null, undefined, Symbol은 불변값

불변성

  • 한번 만든 값을 바꿀 수 없음
  • 변경은 새로 만드는 동작을 통해서 이뤄짐
  • 한번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않음
var a = 'abc'
a += 'def'
  • 변수 a에 문자열 ‘abc’를 할당했다가 ‘def’를 추가
  • 기존의 ‘abc’가 ‘abcdef’로 바뀌는 것이 아님
  • 새로운 문자열 ‘abcdef’을 만들고 그 주소를 변수 a에 저장
  • ‘abc’와 ‘abcdef’는 완전히 별개의 데이터
var b = 5
var c = 5
b = 7
  • (1번째 줄) 변수 영역에 빈 공간 확보 후 식별자로 b 지정
  • 데이터 영역에서 5를 찾음
  • 없으면 데이터 공간을 하나 만들어 5 저장
  • 그 주소를 b에 저장
  • (2번째 줄) 변수 영역에 빈 공간 확보 후 식별자로 c 지정
  • 데이터 영역에서 5를 찾음
  • 이미 만들어 놓은 5의 주소를 재활용함
  • (3번째 줄) 기존에 저장한 7이 있는지 확인 후 없으면 새로 만들어서 그 주소를 b에 저장

참조형 데이터의 할당

var obj1 = {
  a: 1,
  b: 'bbb',
}
  • 변수 영역 빈 공간(@1002)을 확보하고 그 주소 이름(식별자)을 obj1로 지정
  • obj1의 데이터를 저장하기 위해 데이터 영역에 빈 공간(@5001)을 확보
  • obj1에 할당하려는 데이터는 여러 개의 프로퍼티로 이뤄진 데이터 그룹
  • 데이터 그룹 내부의 프로퍼티들을 저장하기 위한 별도의 변수 영역(@7103 ~ ?) 마련
  • 그 별도의 변수 영역의 주소를 @5001에 저장
  • @7103에 프로퍼티 이름 a 지정
  • @7104에 프로퍼티 이름 b 지정
  • 데이터 영역에서 숫자 1 검색
  • 1이 없으므로 데이터 영역의 빈 공간 @5003에 1을 저장
  • @7103@5003 저장
  • 데이터 영역에서 문자열 ‘bbb’ 검색
  • ‘bbb’가 없으므로 데이터 영역의 빈 공간 @5004에 저장
  • @7104@5004 저장

기본형 데이터와 참조형 데이터

  • “객체의 변수(프로퍼티) 영역”이 별도로 존재한다는 점
  • 객체가 별도로 할애한 영역은 “변수 영역”
  • “데이터 영역”은 기존의 메모리 공간을 그대로 활용
  • 데이터 영역에 저장된 값은 모두 불변값
  • 변수에는 다른 값을 얼마든지 대입할 수 있기 때문에 흔히 참조형 데이터는 불변하지 않다고 하는 것

참조형 데이터의 프로퍼티에 참조형 데이터를 할당하는 경우

  • 중첩 객체라고 함
var obj = {
  x: 3,
  arr: [3, 4, 5],
}
  • 변수 영역 빈 공간(@1002)을 확보하고 그 주소의 이름을 obj로 지정
  • obj의 데이터를 저장하기 위해 데이터 영역의 빈 공간(@5001)을 확보
  • obj에 할당하려는 데이터는 여러 개의 프로퍼티로 이뤄진 데이터 그룹
  • 데이터 그룹 내부의 프로퍼티들을 저장하기 위한 별도의 변수 영역(@7103 ~ ?) 마련
  • 그 별도의 변수 영역의 주소를 @5001에 저장
  • @7103에 프로퍼티 이름 x 지정
  • @7104에 프로퍼티 이름 arr 지정
  • 데이터 영역에서 숫자 3 검색
  • 3이 없으므로 데이터 영역의 빈 공간 @5002에 1을 저장
  • @7103@5002 저장
  • @7104에 저장할 데이터는 obj와 마찬가지로 데이터 그룹
  • 데이터 그룹 내부의 프로퍼티들을 저장하기 위한 별도의 변수 영역(@8104 ~ ?) 마련
  • 그 별도의 변수 영역의 주소를 @5003에 저장
  • @7104@5003 저장
  • arr의 배열의 요소가 3개이므로 3개의 변수 공간을 확보하고 각각 인덱스 부여
  • 데이터 영역에서 숫자 3 검색(@5002)해서 그 주소를 @8104에 저장
  • 데이터 영역에 숫자 4가 없으므로 @5004에 저장하고 이 주소를 @8105에 저장
  • 데이터 영역에 숫자 5가 없으므로 @5005에 저장하고 이 주소를 @8106에 저장

중첩 객체에 재할당 명령을 내리면?

obj.arr = 'str'
  • 데이터 영역에 빈 공간 @5006에 문자열 ‘str’ 저장
  • 그 주소를 @7104에 저장
  • @5003은 더이상 자신의 주소를 참조하는 변수가 없게 됨

참조 카운트와 가비지 컬렉터

  • 어떤 데이터에 대해 자신의 주소를 참조하는 변수의 개수를 참조 카운터라고 함
  • 참조 카운터가 0인 메모리 주소는 가비지 컬렉터의 수거 대상이 됨
  • 가비지 컬렉터는 런타임 환경에 따라 특정 시점이나 메모리 사용량이 포화상태에 이를 때마다 자동으로 수거 대상을 수거함

변수 복사할 때 기본형과 참조형 비교

기본형 데이터

var a = 10
var b = a
  • 변수 영역의 빈 공간 @1002 확보 후 식별자 b로 지정
  • 식별자 a 검색(@1001)
  • @1001에 저장된 값인 @5001@1002에 값으로 대입

참조형 데이터

var obj1 = { c: 10, d: 'ddd' }
var obj2 = obj1
  • 변수 영역의 빈 공간 @1004을 확보 후 식별자 obj2로 지정
  • 식별자 obj1 검색(@1003)
  • @1003에 저장된 값인 @5002@1004에 값으로 대입

복사 과정은 동일함

  • 복사하는 과정은 기본형과 참조형 모두 같은 주소를 바라보게 되는 점에서 동일
  • 복사 과정은 동일하지만 데이터 할당 과정에서 이미 차이가 있음
  • 따라서 복사 이후 동작에도 큰 차이가 발생

변수 복사 이후 값 변경 결과 비교

기본형 데이터

var a = 10
var b = a
b = 15
  • 데이터 영역에서 15를 검색 후 없으면 새로운 공간 @5004에 저장
  • 변수 영역에서 식별자 b를 찾아 방금 15를 저장한 주소 @5004를 대입

참조형 데이터

var obj1 = { c: 10, d: 'ddd' }
var obj2 = obj1

obj2.c = 20
  • 데이터 영역에서 20을 검색 후 없으면 새로운 공간 @5005에 저장
  • 변수 영역에서 식별자 obj2를 검색(@1004)
  • obj2의 값인 @5002가 가리키는 변수 영역에서 다시 c를 찾음(@7103)
  • @7103@5005 대입

뭐가 다르지?

  • 기본형 데이터인 변수 a, b는 서로 다른 주소를 바라보게 됨
  • 참조형 데이터인 변수 obj1, obj2는 여전히 같은 객체를 바라봄
a !== b
obj1 === obj2
  • 어떤 데이터 타입이든 변수에 할당하기 위해서는 주소값을 복사해야 함
  • 따라서 엄밀히 따지면 자바스크립트의 모든 데이터 타입은 참조형 데이터일 수밖에 없음
  • 다만 기본형은 주소값 복사를 한 번만 하고, 참조형은 한 단계를 더 거치는 차이가 있음
  • 기본형도 결국 주소값을 참조함

객체 프로퍼티가 아닌 객체 자체를 변경하면?

var a = 10
var b = a
var obj1 = { c: 10, d: 'ddd' }
var obj2 = obj1

b = 15
obj2 = { c: 20, d: 'ddd' }
  • b와 마찬가지로 obj2에도 새로운 객체를 할당함으로써 값을 직접 변경함
  • 메모리의 데이터 영역의 새 공간에 새 객체가 저장되고 그 주소를 변수 영역의 obj2 위치에 저장
  • 객체에 대한 변경임에도 값이 달라짐
  • 따라서 참조형 데이터가 “가변값”이라고 설명할 때의 “가변”은 참조형 데이터 자체를 변경하는 경우가 아니라 그 내부의 프로퍼티를 변경할 때만 성립

Written by@thumbsu
프론트엔드 개발자 엄지수 입니다.

GitHubTwitterLinkedIn