변수&상수 vs. 가변&불변
*[정재남, 데이터 타입: 코어 자바스크립트, 위키북스, 2019.] 를 참고하였고 이해한 바를 작성한 것입니다.
코틀린에서 var, val, mutableCollection, Collection을 어떻게 생각해야 하는가에 대해서 생각해보다 예-전에 자바스크립트를 공부하면서 이런 비슷한 개념을 배웠던 것 같았다. 집에 그 책이 있어 보게되었고 코틀린과 비교하면 좋을 것 같아 다시 한번 더 정리하게 되었다.
이 책을 보게될 당시에 정확히 이해하지 못하고 넘어갔다는 느낌이 들었었는데, 이번에도 뭔가 잘 이해가 되지 않았다. 글쓴이의 의도를 정확히 파악하지는 못한 것 같지만 나름 정리해보려고 한다.
1. 변수랑 상수를 구분짓는 기준이 가변과 불변 아니예요?
이 문장을 일반적으로 마주한다면 맞는 말이라고 생각한다. 다만, 어떤 가변과 어떤 불변이냐를 세부적으로 따져야 한다면 고려할 사항들이 있다.
"변수랑 상수를 구분짓는 기준은 변수영역 내의 메모리에 담긴 내용의 가변과 불변 가능 여부이다." 라고 해야 말이 된다는 것이다.
여기서 나온 '변수영역'을 이해해야 한다.
2. 변수영역과 데이터영역
let variable = 0
과 const value = 0
을 생각해보자.
variable = 1
은 되고 value = 1
은 되지 않는 이유를 메모리를 통해 보자
- 변수명과 메모리의 관계는 아묻따 생각말자
- 메모리 주소에 있는것은 변수와 상수에 할당된 값 자체이다.
라는 것.
자 이제 뭔가 하나는 이상해야 한다.
1)번이 인간적으로는 말이 되지만, 컴퓨터에게는 말이 되지 않는다.
'자 주소 1000이 variable에 할당된 값을 가지고 있는 메모리 영역이야.'
이걸 컴퓨터는 어떻게 알고있을까? 얘한테는 메모리가 머리의 전부인데 어디에 이걸 기억해놓는다는 말인가? 잘 이해가 되지 않는다면 DNS를 생각해보자. \www.something.com을 153.92.92.1라고 바꾸기 위해서는 DNS Table이 어떤 DNS 서버에는 저장되어 있어야 한다. 따라서 여기서 나올 수 있는 결론은 "변수명도 어딘가에 저장되어 있다."가 된다.
이렇게 되면 말이 좀 된다.
그런데 여기서 자바스크립트는 하나의 트릭을 더 보여준다. 그것은 '변수영역'과 '데이터영역'을 나누어서 관리하는 것이다.
'변수 영역'에는 변수명과 데이터영역의 주소값을 저장하고 '데이터 영역'에는 변수나 상수의 '값'을 저장한다.
변수 영역 메모리
데이터 영역 메모리
왜 변수 영역과 데이터 영역을 구분하는지 느낌이 올까?
variable이나 value나 0이 할당되었을 때는 주소 하나만을 참조했다. 변수의 갯수가 많아져도 데이터 영역은 1개만을 가지고 있으면 된다!
1. 자 다시 돌아와서,
그럼 모든 데이터 타입을 이렇게 저장할까? 배열이라면 데이터 영역에 [1, 2, 3] 이렇게 저장하나?
이것을 이해하려면 데이터 타입에 따른 메모리 할당방식도 봐야한다.
3. 데이터 타입별 메모리 할당 방식
기본 타입들(Number, String, boolean, null, undefined, Symbol)은 위와 같은 할당방식을 대입해봤을 때 아무런 문제가 없다.
기본 타입이 아닌 타입들을 참조형 타입이라고 하는데, 이것에는 객체, 함수등이 있다. 객체 중에 대표적인 것이 배열이니 (let or const) arr = [1, 2, 3]
를 예시로 보자.
변수 영역 메모리
데이터 영역 메모리
변수 영역 메모리
주소 | ... | #3001 | #3002 | #3003 | ... |
---|---|---|---|---|---|
데이터 | 변수명: 0 (인덱스) 데이터 주소: #2001 |
변수명: 1 (인덱스) 데이터 주소: #2003 |
변수명: 2 (인덱스) 데이터 주소: #2004 |
이렇게 된다.
참조형은 기본형들의 집합으로 생각하고 보면 이해가 쉽다.
1. 자 진짜 그래서,
"변수랑 상수를 구분짓는 기준은 변수영역 내의 메모리에 담긴 내용의 가변과 불변 가능 여부이다."
변수와 상수를 구분짓는 것은 이해가 된다. 변수 영역 메모리에서 '데이터 주소:' 이 부분이 바뀔 수 있는건 변수 아니라면 상수라는 말이니까.
이것은 책에 내용에도 잘 나와있다.
변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리입니다. 한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건입니다. 반면 불변성 여부를 구분할 때의 변경 가능성의 대상은 데이터 영역 메모리입니다.
-p.9-
그런데, 내가 잘 이해가지 않았던 부분은 '불변성 여부를 구분할 때의 변경 가능성의 대상이 데이터 영역 메모리' 라는 것이다. 위에서 봤을 때 데이터 영역 메모리의 값은 변할 수 없다. 변수에 다른 값이 할당되면 데이터 영역의 새로운 영역에 값이 저장되고 그것의 주소가 변수영역에 저장되는 것이니까. 그리고 어떤 데이터 영역의 주소를 어떠한 변수영역 메모리도 가지고 있지 않다면 GC에 의해서 값이 날라가버리는 것 뿐이니.
그리고 하나의 문장을 더 이해하지 못했는데,
즉, 참조형 데이터가 '가변값'이라고 설명할 때의 '가변'은 참조형 데이터 자체를 변경할 경우가 아니라 그 내부의 프로퍼티를 변경할 때만 가능합니다.
-p.20-
인용한 두 문단을 같이 생각해 봤을 때, 내부의 프로퍼티를 변경할 때 가능하다는 말은 프로퍼티의 데이터 영역 메모리를 변경할 때만 가능하다는 말이라고 이해하게 된다. 데이터 영역 메모리는 변경이 불가하지 않은가?... 이 부분에서 과거에도 지금도 막혔었다. 결국 저자의 의도를 제대로 파악하지 못했다는 생각이 드는데, 나름의 결론은 다음과 같다.
4. 참조형은 가변형이다. 왜?
참조형들은 데이터 영역에 프로퍼티의 변수 영역 주소를 저장한다.
변수 영역은 데이터 영역의 주소를 저장한다.
(변수 영역에 저장하고 있는 식별자가 상수가 아니라 변수라면) 변수 영역이 저장하고 있는 데이터 영역 주소는 달라질 수 있다.
1.변수 영역(have (2.데이터 영역 주소 -> have (3.변수 영역 주소 -> have (4.데이터 영역 주소)))
3.은 4.를 다른 4.로 바꿀 수 있다.
그래서 참조형은 가변형이다.
이렇게 보니 어떻게 보면 저자가 말하고자 했던게 이해가 된다.
'데이터 영역 메모리가 가지고 있는 변수 영역 메모리가 가지고 있는 값이 변경될 수 있는지의 여부.'이지 않았을까.
5. 그래서 불변성이 왜 중요한데?
const mutableObj1 = {
a: 1,
b: {
name: 'youngsoo',
gender: 'male'
}
}
const mutableObj2 = mutableObj1
console.log(mutableObj1); //{ a: 1, b: { name: 'youngsoo', gender: 'male' } }
console.log(mutableObj2); //{ a: 1, b: { name: 'youngsoo', gender: 'male' } }
mutableObj2.b.gender = 'female' //????
console.log('-------------');
console.log(mutableObj1); //{ a: 1, b: { name: 'youngsoo', gender: 'female' } } //????
console.log(mutableObj2); //{ a: 1, b: { name: 'youngsoo', gender: 'female' } }
네, 이래서 중요합니다.
의도치 않게 값이 바뀔 수 있습니다.
아무리 참조형을 상수에 할당 했다고 한들 이렇게 됩니다.
가변 객체를 사용하는 것을 주의해야 하는 이유입니다.
많은 언어들이 이를 위해 노력하고 있는 것이 보입니다.
Swift에서 구조체에 mutating 키워드를 사용하도록 하는 것과, 코틀린은 mutable과 immutable을 구분하기 위해 노력하는 것 처럼요.
6. 데이터 영역의 값 == 리터럴 (+240717)
이 책에서 얘기하는 데이터 영역에 넣어주는 값이 코드에 표현된 것을 '리터럴'이라고 하는 것 같다. (참고)