[자바스크립트 Deep Dive] 데이터 타입

자바스크립트는 7개의 데이터 타입이 있다. 근데 이제 ES11에서 BigInt가 추가된

6. 데이터 타입

7개의 데이터 타입은 원시타입과 객체타입으로 구분할 수 있다.


숫자타입의 1과 문자열 타입의 '1'은 생김새는 비슷할지언정 전혀 다른 값이다.
우선 생성한 목적과 용도가 다르고 두개의 다른 데이터 타입은 서로 확보해야 할 메모리 공간의 크기도 다르며 메모리에 저장되는 2진수도 다르다. 당연히 2진수도 읽어 들여 해석하는 방식도 다르고 값도 다르다.

6.1. 숫자 타입

자바스크립트에게 숫자는 그냥 숫자다. 그게 정수던 실수던


ECMAScript 스팩에 따르면 숫자 타입의 값은 배정밀도 64비트 부동소수점 형식을 따른다는데 간단히 말해 모든 숫자를 실수로 처리한다는 뜻이다. 즉 자바스크립트에게 숫자타입은 실수뿐이다.

var binary = 0b01000001; //2진수
var octal = 0o101; // 8진수
var hex = 0x41; // 16진수

위 예제에서 각 변수에 할당된 평가된 값들은 모두 메모리에 배정밀도 64비트 부동소수점 형식의 2진수로 저장된다고 한다. 즉 각 진수에 따른 별도의 데이터 타입이 제공되지 않기 떄문에 위 평가된 값들은 모두 같다.

var binary = 0b01000001; //2진수
//65
var octal = 0o101; // 8진수
//65
var hex = 0x41; // 16진수
//65

console.log(binary === octal) 
// true
console.log(octal === hex)
// true

심지어 정수와 실수 또한 아래와 같이 평가된다.

console.log(1 === 1.0)
// true

하지만 또 아래와 같은 현상도 존재한다.

const a = 0.1
const b = 0.2

console.log(a+b === 0.3);
//false
console.log(0.30000000000000004 === a + b);
//true 


console.log(a === 0.10)
//true
console.log(a === 0.1000000000000001)
//false
console.log(a === 0.10000000000000001)
//true

console.log(0.300000000000000004 === a + b);
//false 
console.log(0.30000000000000004 === a + b);
//true 

이는 배정밀도 64비트 부동소수점 형식떄문이라는데 자세한 내용은 아래 링크에
또한 추후에 정리할 예정이다. (아마 책 뒤에 내용이 나오지않을까 싶은데)
간단하게만 정리하자면 컴퓨터는 비트에 담긴 0과1을 사용해서 이진법으로 숫자를 표현하기 때문에 표현할 수 있는 숫자의 개수는 비트 수에 정비례한다. “유한개”인 표현방법으로 “무한개” 인 모든 수(실수)를 표현할 수 없기 때문에, 정확도를 낮추는 대신 표현할 수 있는 범위를 넓히는 방향을 택할 수 있다.
즉 자바스크립트는 정확도를 낮추는 대신 표현할 수 있는 범위를 넓히는 방향을 택한것이다.
자바스크립트 64비트 부동 소숫점
자바스크립트 소수점 계산 오류

6.2. 문자열 타입

텍스트


문자열 타입은 0개 이상의 16비트 유니코드 문자 (UTF-16)의 집합으로 작은따옴표, 큰따옴표 또는 백틱으로 감싸주면 문자열로 평가된다.
문자열은 원시 타입으로 변경 불가능한 값 (immutable value)이다. 문자열이 생성되면 그 문자열을 변경할 수 없는 이는 추후에 더 자세한 내용이 나온다.

6.3. 템플릿 리터럴

백틱


백틱을 따옴표 대신 사용하여 감싸진 문자열이다.
일반 문자열에서 허용됮 않는 개행이 허용되고 표현식또한 삽입할 수 있다.

/*
`나는
아직
배고프다
`
*/
`나는
아직
배고프다
`

const lastName = "Lee"
const firstName = "Jouz"
const greeting = `제 이름은 ${firstName} ${lastName} 입니다.`
console.log(greeting)
// 제 이름은 Jouz Lee 입니다. 

6.4. 불리언 타입

논리적으로 참 거짓을 나타내는 true와 false 뿐이다.
빈 문자열과 숫자 0은 falsey 하다.
자바스크립트한테 ''0은 논리적으로 거짓이라고 해석해도 될까?

6.5. undefined 타입

undefined는 개발자가 의도적으로 할당하기 위한 값이 아니라 자바스크립트 엔진이 변수를 초기화 할 떄 사용하는 값이다.
자바슼므립트 엔진이 변수를 초기화하는 데 사용하는 undefined를 개발자가 의도적으로 변수에 할당한다면 본래 취지와 어긋날뿐더러 혼란을 줄 수 있으므로 권장하지 않는다고 한다.

6.6. null 타입

위 undefined처럼 변수에 값이 없다는 것을 명시하고 싶을 때 사용할 수 있는 타입으로 null 값이 유일하다. null은 변수에 값이 없다는 것을 의도적으로 명시할 수 있고 변수에 null을 할당한다는 것은 이전 참조값을 더 이상 참조하지 않겠다는 의미다. 즉 이전 할당 값에 대한 참조를 명시적으로 제거하는 것 또한 의미할 수 있다.

하지만 typeof를 통해 null의 타입을 확인해보면 아래와 같다.

console.log(typeof null)

// object

이에 대한 논리적인 이유는 없고 because the spec says so

6.7. 심볼 타입

ES6에서 추가된 다른값과 중복되지 않는 유일무이한 값


주로 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용된다.
심벌 이외의 원시 값은 리터럴을 통해 생성하지만 심벌은 Symbol함수를 호출해 생성한다.
이렇게 생성된 심볼값은 외부에 노출되지 않으며, 다른 값과 절대 중복되지 않는 유일무이한 값이다.

6.9. 데이터 타입의 필요성

데이터 타입에 따라 저장할 메모리 공간을 경제적으로 확보하고, 저장된 메모리의 범위를 미리 알 수 있게 되며, 해석에도 사용된다.


자바스크립트 엔진은 값을 메모리에 저장하기에 앞서 저장할 공간을 미리 확보한다.
즉 데이터 타입에 따라 먼저 확보해야할 메모리 공간의 크기가 결정된다.
이는 값을 저장할 때 낭비와 손실을 없애기 위함이다.

또한 앞서 메모리에 값이 저장될 때 2진수의 값으로 저장된다 정리하였고 메모리 셀 하나의 크기는 1바이트라고 정리하였다.
그렇다면 만약 8비트 크기의 숫자 값을 메모리에 저장한다고 가정한다면 8개의 셀이 필요하고 바꿔말하면 8개의 메모리 주소가 변수에 할당된다는 뜻이다.

이때 8비트 크기의 값을 참조한다고 가정해보면 데이터 타입의 필요성을 더 정리해볼 수 있다.
우선 참조 시 변수명 혹은 식별자를 통해 숫자 타입의 값 100이 저장되어 있는 메모리 공간의 선두 메모리 셀의 주소를 찾아갈 수 있다
그 후 데이터 타입을 통해 한번에 읽어 들여야 할 메모리 공간의 크기 또는 셀의 개수를 알 수 있게된다.
더 나아가 특정 메모리 공간에 저장된 2진수 값을 해석할 때 데이터 타입은 필수적이다.
같은 2진수 값이여도 데이터 타입에 따라 해석한 값이 달라지기 때문이다.

정리하자면

  • 값을 저장할 떄 확보해야 하는 메모리 공간의 크기를 결정하기 위해
  • 값을 참조할 때 한 번에 읽어 들여야 할 메모리 공간의 크기 (범주)를 결정하기 위해
  • 읽어 들인 2진수 값을 어떻게 해석할지 결정하기 위해

데이터 타입이 필요하다.

6.10. 동적 타이핑

동적 타입 언어와 정적 타입 언어중 자바스크립트는 동적 타입 언어이다.
자바스크립트는 변수의 선언과 할당 단계가 나누어져있는데 선언이 아닌 할당에 의해 타입이 결정된다.
타입 결정은 타입 추론으로도 볼 수 있고 재할당에 의해 변수의 값이 변하듯 타입 또한 변할 수 있다.
동적 타입 언어는 유연성은 높지만 신뢰성은 떨어진다. 잘못된 타입 추론과 예측으로 복자성이 증가되고 처리 흐름을 추적하기 어렵기 때문이다. 우리가 변수명에 신경써야 하는 이유이기도 하다.


자바스크립트는 변수를 선얼할 때 타입을 선언하지 않는다. 다만 키워드를 사용해 변수를 선언하는데 미리 선언한 데이터 타입의 값만 할당 할 수 있는 것이 아닌 어떠한 데이터 타입의 값도 자유롭게 할당할 수 있다.
또한 변수는 데이터 타입을 갖지 않는다고 볼 수 있고 변수에 할당되어 있는 값에 의해 변수의 타입이 동적으로 결정된다고 표현하는게 더 정확하다.

정적 타입 언어는 변수 선언 시점에 미리 변수의 타입을 선언하여 결정되고 변수의 타입을 변경할 수 없지만 자바스크립트는 값을 할당하는 시점에 변수의 타입이 동적으로 결정되고 변수의 타입을 언제든지 자유롭게 변경할 수 있다.
정리하자면 자바스크립트의 변수는 선언이 아닌 할당에 의해 타입이 결정 (타입 추론) 된다. 그리고 재할당에 의해 변수의 타입은 언제든지 동적으로 변한다.
이러한 특징을 동적 타이핑이라고 하며 자바스크립트를 정적 타입 언어와 구별하기 위해 동적 타입언어라 한다.

변수 값이 언제든지 변경될 수 있는 자바스크립트이기에 복잡한 프로그램에서는 변화하는 변수 값을 추적하기 어려울 수 있을뿐더러 해당 변수의 타입도 언제든지 변경될 수 있기에 값을 확인하기 전에는 타입을 확신하기 어렵다.
또한 개발자의 의도와 상관없이 자바스크립트 엔진에 의해 암묵적으로 타입이 자동으로 변환되기도 한다.
따라서 자바스크립트와 같은 모든 동적 타입 언어는 유연성은 높지만 신뢰성이 떨어질 수 밖에 없고 다음처럼 변수를 사용할 떄 주의해야한다.

  1. 필요한 경우에 한해 제한적으로 사용한다. 변수 값은 재할당에 의해 언제든지 변경될 수 있음으로 잘못된 타입 예측에 의한 오류 발생 가능성이 크고 이는 변수가 많이 사용될 수록 오류가 발생할 확률도 높아진다는 뜻이다. 따라서 변수의 무분별한 남블을 삼가하고 필요한 만큼 최소한으로 유지 하도록 주의해야 한다.

  2. 변수의 유효범위, 즉 스코프를 최대한 좁게 만들어 부작용을 억제해아한다. to be continue CH.13 스코프

  3. 어디서든 참조/변경 가능한 전역변수 사용을 최소화한다. 전역 변수는 모든곳에서 참조, 변경이 가능하기에 의도치 않게 값이 변경될 가능성이 더 높고 이는 다른 사용처에서의 오류를 발생시키는 등 코드에 영향을 준다. 이는 곧 처리 흐름을 추적하기 어렵게 만들고 오류의 원일을 특정하기 어렵게 만든다. to be continue CH.14 전역 변수의 문제점

  4. 변수보다는 상수를 사용해 값의 변경을 언제한다. to be continue CH.15 const 키워드

  5. 변수 이름은 변수의 목적이나 의미를 파악할 수 있도록 네이밍한다. 개발자의 의도를 나타내는 명확한 네이밍은 코드를 이해하기 쉽게 만들고 이는 협업과 생산성 향상에 도움을 준다.

정리하며

자바스크립트의 데이터 타입은 크게 원시타입과 객체 타입으로 나누어 볼 수 있고 또한 원시타입은 7가지로 나누어볼 수 있다. 데이터 타입은 간단하지만 중요하게 짚고 넘어가볼 필요가 있다.
그 이유는 기본적으로 데이터 타입에 의해 메모리 공간을 미리 확보하고 정확한 위치로 참조할 수 있기 때문이다. 또한 가장 중요하게 데이터 타입에 의해 값의 해석이 달라지기 때문이다.
또한 자바스크립트는 동적 타입 언어로서 7가지의 원시타입간뿐 아니라 모든 데이터 타입간 재할당에 의해 변수의 타입은 동적으로 변할 수 있다.
이처럼 자바스크립트는 유연하지만 신뢰성이 떨어진다. 그렇기 때문에 타입스크립트를 써야한다. ㅎㅎ

좋은 웹페이지 즐겨찾기