
오늘은 자바스크립트의 가장 기초적이면서도, 시니어 개발자가 되어서도 끊임없이 마주하게 되는 **자료형(Data Type)과 변수(Variable)**에 대해 깊이 있게 정리해 보려 합니다.
자바스크립트는 느슨한 타입(loosely typed) 언어이기에 자료형에 대한 명확한 이해가 없으면 런타임 에러를 마주하기 십상입니다. 특히 숫자형과 빈 값을 다루는 방식에서 독특한 특징들이 있습니다.
NaN은 이름 그대로 "숫자가 아님"을 뜻하지만, 아이러니하게도 typeof 연산자로 확인해 보면 number 타입으로 분류됩니다.
컴퓨터가 부동소수점 숫자를 다루는 표준 규격인 IEEE 754를 따르기 때문이다. 이 표준에서는 수학적으로 정의되지 않은 수치 값을 표현하기 위한 숫자 타입의 특수한 상태를
NaN으로 지정했다.
Infinity는 무한을 나타내는 숫자이다.
역시 number타입으로 취급된다.
실무에서 Infinity는 주로 비교 알고리즘의 초기값으로 사용할 수 있다고 한다.
예를 들어, 배열에서 가장 작은 숫자(최솟값)를 찾아야 하는 로직을 짤 때, 최솟값을 저장할 변수의 초기값을 Infinity로 설정해 둡니다.
그러면 배열의 어떤 숫자와 비교하더라도 첫 번째 비교 대상이 무조건 더 작게 되므로 로직이 안전하게 동작합니다. 반대로 최댓값을 구할 때는 -Infinity를 초기값으로 사용하기도 합니다.
소수 계산에서 주의할 점이 있다.
거의 모든 프로그래밍 언어에서 아래와 같은 상황이 발생한다. (부동소수점 계산)
0.1 + 0.2 // 0.30000000000000004
컴퓨터는 모든 데이터를 **0과 1 (2진수)**로 저장한다.
우리가 사용하는 0.1이나 0.2 같은 10진수 소수는 2진수로 변환하면 딱 떨어지지 않고 무한 소수가 되어버린다.
하지만 컴퓨터의 메모리는 유한하기 때문에, 이 무한 소수를 어딘가에서 잘라내어(근사치) 저장하게 됩니다. 이 저장 방식이 바로 '부동소수점(Floating Point)' 방식이라고 한다.
이 미세한 오차들이 더해지면서 0.3이 아닌 아주 미세하게 큰 값이 출력되는 것입니다.
실무에서는 돈 계산과 같이 정확도가 중요한 경우 decimal.js 같은 라이브러리를 사용하거나, 정수로 변환하여 계산 후 다시 나누는 방식을 사용하면 된다고 한다..
두 값 모두 '없음'을 나타내지만, 그 뉘앙스와 사용 목적은 완전히 다르다.
undefined는 **'아직 값이 할당되지 않음'**을 의미합니다.
변수를 선언만 하고 값을 넣지 않았거나, 값을 반환하지 않는 함수를 호출했을 때 자바스크립트 엔진이 자동으로 할당하는 값이다.
즉, 개발자가 의도한 것이 아니라 시스템이 비어있음을 나타내는 상태이다.
크롬 개발자 도구 콘솔 부분에서
console.log()명령어를 실행하게 되면, 콘솔에 무언가를 출력하지만, 그 자체로는 값이 없기 때문에undefined가 출력되는 것을 확인해볼 수 있다.
반면 null은 개발자가 '값이 비어있음'을 명시적으로 표현하기 위해 사용하는 값입니다. "이 변수에는 아무런 객체도 들어있지 않아"라고 의도적으로 표시할 때 사용합니다.
undefined == null // true
undefined === null // false
typeof undefined // "undefined"
typeof null // "object"
둘 다 빈 값을 의미하기 때문에 ==연산자로 비교하면 true로 결과를 확인할 수 있지만, 타입이 다르기 때문에 === 연산자로 비교하게 되면 false가 출력되는 것을 볼 수 있다.
null은 원래 타입이null이어야 하지만, 자바스크립트 초기 설계 실수로 비롯된 버그로 인해 타입이object로 출력되는 것을 확인할 수 있다.
하지만 이를 수정하면 기존 웹 생태계의 수많은 사이트가 망가질 수 있어, 울며 겨자 먹기로 유지되고 있다고 한다,,
변수 내에서 null 은 '값이 없음' 을 명시적으로 표현할 때 사용. (의도적)
변수 내에서 undefined 는 '값이 할당되지 않음' 을 의미. (의도적이지 않음, 있어야 하는데 없는 경우)
동작 자체는 두 가지 다 비슷하지만, 의미가 다르기 때문에 구분해서 사용해야 한다.
'5' == 5 // true
'5' === 5 // false
==연산자 : 값(데이터)만 비교.===연산자 : 값과 타입까지 비교.자바스크립트의 타입 변환 규칙이 복잡하고 예측하기 어려워서 의도치 않은 결과가 나올수 있기 때문에 요즘은 ==연산자 대신 ===연산자를 더 권장한다.
컴퓨터에서의 값 사용은 일회용이다. 기억을 못한다.
값을 재사용하기 위해서는 값을 저장할 그릇이 필요한데, 변수라는 그릇을 사용한다.
변수는 컴퓨터 메모리 어딘가에 저장된다.
휘발적인 메모리 주소를 변수 이름으로 대신 사용하게 된다.
자바스크립트에서 변수 정의할 때 let, const, var 를 사용한다.
var 는 variable(변수)의 약자.
var 는 변수 선언 키워드로, ES6 이전에 사용되던 방식이다.
console.log(name); // undefined (에러 안 남, 호이스팅???)
var name = 'Kim';
if (true) {
var age = 20; // 블록 안에서 선언했지만
}
console.log(age); // 20 (전역에서 접근 가능해버림)
var name = 'Lee'; // 재선언 가능 (기존 값 덮어씀)
if 문이나 for 문과 같은 블록 스코프를 무시하고 함수 스코프 내에서만 지역 변수로 작동한다.
같은 이름의 변수를 여러 번 선언할 수 있어, 의도치 않은 변수 재선언으로 인한 버그 발생 가능성 존재한다.
ES6 이후 let 과 const 가 도입되면서 var 의 사용은 권장되지 않는다.
호이스팅에 관한 글을 따로 작성해봐야겠다..
ES6부터는 블록 스코프(Block Scope, {})를 따르는 let과 const가 도입되어 변수 관리가 훨씬 안전해졌다.
let: 값을 재할당할 수 있는 변수이다. 값이 변해야 하는 루프 카운터나, 상태 값 등에 사용한다.
const: 상수를 선언합니다. 한 번 할당하면 재할당이 불가능하다.
const로 선언된 변수는 재할당이 안 될 뿐, 그 값이 객체나 배열인 경우 내부의 속성은 변경할 수 있다.
즉, 변수가 가리키는 메모리 주소(참조)가 고정되는 것이지, 값 자체가 불변(Immutable)이 되는 것은 아닙니다.
const 를 사용하여 변수를 선언. (의도치 않은 재할당 방지)let 을 사용하여 변수를 선언.var 는 사용하지 않음. (예전 방식, 호이스팅 및 스코프 문제로 인해 권장되지 않음)오늘 자료형과 변수 파트를 정리하면서,
NaN의 정체, 부동소수점 계산의 원리, 그리고 undefined와 null의 명확한 차이에 대해 새롭게 리마인드 할 수 있었다.
졸업을 앞두고 다시 기초를 공부하다 보니, 단순히 기능을 구현하는 것보다 '왜?'라는 질문을 던지며 원리를 파고드는 과정이야말로 진짜 실력을 키우는 지름길이라는 생각이 든다.
Next: [JS 기초 학습] 03. 객체