2022년 11월 10일
자바스크립트 데이터에는 2가지 타입이 있습니다.
우리는 기본형은 값의 주솟값을, 참조형은 값이 담긴 주솟값들에 묶음을 가리키는 주솟값을 복제한다고 알고있습니다.
그런데 처음 배웠을 당시 기본형은 불변성을 가지고, 참조형은 가변성을 가진다는 말이 잘 이해가 되지 않았습니다.
오히려 반대아니냐고 생각했었죠. 오늘은 그 개념을 정확하게 짚고, 더 나아가 숫자형 데이터타입에 관한 배경지식을 정리해보려 합니다.
자 먼저 변수에 값을 할당해봅니다.
var num = 1
이렇게 변수를 선언한 순간 메모리에서는 이런식으로 읽는다고 합니다.
var num = 1
num이라는 변수를 10번이라는 방에 저장됩니다.
1의 데이터는 20번이라는 방에 저장됩니다.
10번 방문을 열면 바로 20번 방과 연결됩니다.
이때 num = 2 라고 변수에 새로운 값을 할당한다면
num이라는 변수는 10번방 그대로입니다.
2의 데이터는 21번이라는 방에 저장됩니다.
그리고 10번방은 이제 새로운 21번방과 연결됬습니다.
즉 변수가 바라보고 있는 데이터의 입장에서는
새로운 데이터가 변수와 연결되려면
새로운 방을 연결해야합니다.
절대 자기자신이 변경될수는 없습니다.
이것을 보고 기본형 데이터는 불변성을 띈다고 합니다.
이걸보면 결국 데이터를 새로 선언하면 새로운 방에 저장이 되며, 결국 다 불변성을 띄는거 아니냐고 생각할수 있습니다. 제가 그렇게 생각했으니까요.
그럼 참조형의 경우를 보겠습니다.
var object: {
num_1: 1,
num_2: 2,
}
새로운 객체를 만들고 객체 안에 값을 넣었습니다. 이때 어떤식으로 처리가 될까요?
var object : {
num_1:1,
num_2:2
}
object 라는 객체를 10번방에 저장합니다.
num_1이라는 key(변수)를 20번방에 저장합니다.
num_2이라는 key(변수)를 21번방에 저장합니다.
1의 데이터를 30번방에 저장합니다.
2의 데이터를 31번방에 저장합니다.
이제 10번방에 문을 열면 20번,21번방의 문이 보이고,
각 20번,21번방은 30번,31번방과 연결되어있습니다.
이때 object.num_1 = 3 이라고 값을 변경한다면
3의 데이터를 32번방에 저장하며,
20번방은 32번방과 새로 연결된것이 됩니다.
즉 객체가 바라보고 있는 데이터(변수)의 입장에서는
객체와 연결된채로 자기자신의 값을 바꾸는 것이
가능합니다. 그저 새로운 값의 방만 연결할 뿐입니다.
이것을 보고 참조형 데이터는 불변성을 띈다라고 합니다.
아직도 많은것을 모르지만 이젠 적어도 자바스크립트에서 변수를 선언할때 최소한 어떤식으로 선언되는지는 알게됬습니다.
컴퓨터는 0과1의 세계라고 합니다.
그 0과1만을 표현할수 있는 하나의 메모리 조각을 비트라고 합니다.
이런 비트를 8개 묶어 표현하는것을 1바이트라고 합니다. 1바이트는 총 256개(2^8)의 값을 표현할수 있습니다.
옛날에는 하나의 데이터에 몇개의 바이트로 표현할것인가에 대해 개발자가 직접 할당을 했지만, 현대에서는 많은 메모리 제약이 사라졌고, 이 덕분에 자바스크립트 내에서 숫자의 경우 정수형인지, 부동소수형인지 구분하지 않고 8바이트를 확보할 수 있게 되었습니다.
그런데 8바이트를 확보하고 있다는 말은 결국 저장할수 있는 숫자의 범위가 한정적이라는 뜻입니다.
이게 무슨말이냐면 직접 변수에 큰 숫자를 넣어보면 됩니다.
const maxNum = 9223372036854775807;
콘솔로그를 찍어보자!
console.log(maxNum) // 9223372036854776000
자 숫자가 정확하게 표현되지 않았습니다.
그리고 친절하게 왜 안되는지 알려주기까지 합니다.
절대값이 2^53보다 크거나 같은 숫자 리터럴은
너무 커서 정수로 정확하게 표시할 수 없습니다.
우리는 아까 자바스크립트는 숫자에 대해서는 기본적으로 8바이트를 확보하고 있다고 알게됬습니다.
즉 2^64까지의 값만 변수에 넣을수 있는것이죠. 그런데 에러를 보면 2^53과 같거나 큰 숫자라고 합니다. 너무 억울하죠. 내가 쓰지도 않는 나머지는 어디로 갔을까요?
이것을 알기 위해 조금 돌아가보면.. 우리세상에 숫자는 크게 2가지 타입이 있습니다. 실수와 정수입니다. 우리 세상에 모든숫자는 실수로 나타낼수 있으며, 정수는 실수의 부분집합입니다.
그런데 사실 실생활에서는 정수를 더 많이 사용하기도 하고, 그토록 많은 (사실상 무한에 가까운) 실수를 모두 데이터안에 담기에는 한계가 있는것이 자명했습니다.
그렇기에 정확도를 낮추는 대신 표현할수 있는 범위를 늘리기로 합니다. 그 결과 64비트를 쪼개어 가수, 지수, 부호로 나누었으며 우리가 정확하고 안전하게 표현할수 있는 숫자는 2^53까지라고 합니다.
(정확하게는 2^53-1까지라고 하는데 이유는 다음번에 정리해봅시다.)
자 그럼 왜 못넣는지도 알았으니 간단하게 어떻게 하면 넣을수 있는지도 짤막하게 알아봅시다.
BigInt라는 것이 있습니다. 이것은 최대,최소범위를 초과한 정수를 안전하게 저장하고 비교하기 위해 만들어진 JS의 새로운 데이터 형입니다.
2^53을 초과한 데이터 뒤에 n을 붙이거나 BigInt()를 호출하여 사용하면 된다고 합니다.
이때 해당 타입은 Number가 아닌 BigInt이며, 일반 숫자와 혼합하여 사용할수 없습니다. 이때 일반 숫자형도 모두 BigInt로 바꿔줘야 합니다.
또한 BigInt를 Number로 바꾸면 정확성을 잃을수 있다고 하니 조심하여 사용해야 합니다.
const bigNum = 100n
console.log(typeof bigNum) // BigInt
console.log(bigNum === 100) // false
console.log(bigNum + 1) // TypeError
//Cannot mix BigInt and other types, use explicit conversions