...
자바스크립트의 요상한 falsy 값
자바스크립트에서 null, NaN, undefined는 다른 프로그래밍 언어에는 없는 자바스크립트에만 있는 요상한 falsy 값으로서, 이들은 모두 값이 없음(falsy)을 나타내는 특별한 값이다. 그래서 이들은 조건문에서 false로 평가되어 진다.
값 | Boolean 문맥 | Number 문맥 | String 문맥 |
null | false | 0 | "null" |
undefined | false | NaN | "undefined" |
NaN | false | NaN | "NaN" |
Infinity | true | Infinity | "Infinity" |
하지만 대부분 null, NaN, undefined 간의 의미의 구체적인 차이에 대해 애매모호하게 알거나 정확히 모르는 사람이 꽤 많다. 따라서 이번 포스팅에는 null, NaN, undefined값을 두루마리 휴지로 비유한 이미지를 통해 정확히 어떤 의미이며 왜 이러한 의미인지 알아보는 시간을 가져 보겠다.
두루마리 휴지로 비유하는 falsy 값
위 이미지는 자바스크립트 falsy 값에 대한 일종의 유머적 비유이다. 모두 의미 없거나 부적절한 값들이지만 휴지 형태에 따라 확실히 의미하는 바가 다름을 볼 수 있다. 이들 4개의 값을 설명하자면 다음과 같다.
0 의 상태
정수 0은 대다수 프로그래밍 언어에서 false로 평가된다. 이를 휴지로 비유하면 휴지 내용물이 없다는 의미이다. 단, 0 이라도 고유한 숫자 타입 이듯이 휴지 내용물이 없어도 휴지임을 알 수 있는 '곽티슈' 와 이를 담는 '휴지걸이'는 잔존한다.
null 의 상태
보통 null을 그저 값이 없는 상태라고 알고 있는 분들이 많지만, 이는 정확하지 않은 의미이다. 정확히 null은 어느 reference 변수에 대해 주소값이 없는 것을 표현하기 위한 키워드 값이다. 객체의 속성 값이 존재하지 않을 때나 함수의 매개변수를 초기화하는 용도로 사용 되기도 한다.
레퍼런스 변수란 객체와 같이 힙(heap) 공유 메모리 영역에 저장되는 포인터 라고 이해하면 된다.
그런데 null은 오로지 reference 변수에만 담을 수 있기 때문에, 일반적인 값인 정수나 문자를 저장하는 primitive 변수에는 null을 저장할 수 없다. 따라서 Java에서는 이 primitive 변수에 대해 값을 주지 않을 경우 지정된 초기화 값을 자동으로 할당하게 하였고, C언어에서는 가비지 값을 자동으로 할당한다.
#include <stdio.h>
int main() {
int num;
printf("%d", num); // -56982792084 이상한 쓰레기 값
return 0;
}
public class MyClass {
int number; // 인스턴스 변수
public static void main(String[] args) {
MyClass obj = new MyClass();
System.out.println(obj.number); // 출력 결과: 0 (원래는 C언어 처럼 쓰레기값이 나오지만 JVM에 의해서 기본값으로 설정된다)
}
}
reference 변수냐 primitive 변수냐 에 따라 타입이 없는 자바스크립트로도 알수가 있는데, 1을 할당한 변수의 타입은 number 타입이지만, null을 할당한 변수의 타입은 object 임을 알 수가 있다.
결론적으로, 위의 0과 다른점은 곽티슈는 없지만 휴지걸이는 잔존해 있다는 점이다. 왜냐하면 null 값을 들고 있는 객체 자체는 프로그래머가 정의하여 메모리에 올려져 주소값을 받은 준비가 되어 있기 때문이다.
즉, 값은 없지만 값을 담을 수 있는 그릇은 있는 것이다. 따라서 휴지를 담는 휴지걸이 자체는 잔존해 있는 것이다.
undefined 의 상태
undefined는 변수가 정의되어 있지 않은 상태, 즉 값이 할당되지 않은 상태를 나타낸다.
바로 위에서 primitive, reference 변수를 들며 자바와 C언어에서 어떻게 초기화를 진행하는지에 대해 설명하였었다. 두 언어만 하더라도 어떤 타입의 변수냐에 따라 초기화되는 과정이 달랐다.
따라서 자바스크립트에선 심플하게 어떤 타입의 변수든 간에 값이 없다는걸 undefined 라는 표현으로 퉁쳤다고 보면 된다. 심지어 변수 타입 자체도 undefined 로 되어 있다. 심플하게 표현하기 위해 이러한 방식을 취한것 같은데, 만일 기존의 C언어나 자바에 익숙한 개발자들에겐 오히려 혼동만 일으킨 것 같다고 개인적으로 생각된다.
null vs undefined
null과 undefined 차이점은 내부 메모리적인 측면에서 봐야 된다.
undefined는 변수가 초기화되지 않았거나, 객체의 속성이 존재하지 않는 등의 경우에 자동으로 할당되는 값으로, 이때의 변수는 메모리에 존재하지만 값이 없기 때문에 크기가 매우 작다.
반면, null은 개발자가 의도적으로 값이 없음을 할당한 경우에 사용되는 값으로, 이때의 변수는 빈 객체를 가리키는 객체 포인터이기 때문에 주소값을 나중에라도 받기위해 크기가 있어 메모리를 차지하게 된다.
따라서, undefined 값을 가진 변수의 메모리 용량은 작고, null 값을 가진 변수의 메모리 용량은 크다고 정리할 수 있겠다. (이는 상대적인 비교일 뿐이므로 실제로는 거의 차이가 없다고 봐도 된다)
다만, 자바스크립트에서는 변수가 컴파일 시점이 아닌 런타임 시점에 동적으로 할당되기 때문에, 변수의 크기는 런타임 환경에 따라 다를 수 있어 메모리 크기는 정확히 알 수 없다.
반면 자바(Java)에선 reference 변수 같은 경우 32비트 JVM 기준으로 4바이트가 할당되게 된다.
null 과 undefined가 서로 완전히 다른 존재라는 점은, 자바스크립트에서 타입을 출력해보면 알 수 있다.
마지막으로 휴지로 비유한 그림을 보면 아예 빈 공간임을 볼 수가 있는데, 휴지 내용물도 그 휴지를 담을 휴지걸이 자체도 없기 때문이다. 왜냐하면 타입 자체가 undefined 이기 때문이다.
위에서 null을 비유할때 아무것도 담기지 않은 그릇이라 표현했는데, undefined는 그릇 자체가 통째로 없는 것이다.
NaN 의 상태
NaN은 Not a Number의 약자로 숫자가 아닌 값을 나타낸다. 그러나 숫자가 아니지만 타입은 Number 타입으로 취급된다. 숫자 타입이면서 숫자가 아닌 값이라니 뭔가 말이야 방구야 싶겠지만, 실제로 이러한 표현에 대한 필요성이 존재한다.
예를들어 문자 "100" 을 숫자 타입으로 형변환하면 어떠한 에러 없이 숫자 100으로 치환이 된다. 이러한 기능이 있는 이유는 대부분의 사용자가 입력한 값이 문자열 형태인 경우가 많아 이를 숫자로 변환하여 계산해야 하는 상황이 많기 때문이다.
그런데 해당 문자가 "100ABC" 와 같은 숫자와 일반 문자열이 섞인 형태일 경우, 이를 함수를 통해 숫자로 변환할때 문제가 된다. 그래서 타입 자체는 넘버 타입으로 변환은 됬지만 내용물이 숫자가 아니라는 값을 표현하기 위해 NaN 이라는 표현을 쓰는 것이다. 그래서 NaN은 일종의 오류 값으로 취급된다. 이밖에도 숫자와 문자열을 연산하려고 해도 NaN이 발생한다.
반면 자바(Java)에선 문자열이 유효한 숫자 형식이 아닐경우 NumberFormatException을 발생시킨다.
// 문자 100을 + 연산자를 통해 숫자로 형변환
let a = +"100";
console.log(a); // 숫자 100
// 문자 ABC를 + 연산자를 통해 숫자로 형변환
let b = +"ABC";
console.log(b); // NaN (숫자로 형변환해서 숫자 타입 값이지만 숫자가 아님)
이를 휴지로 비유하면 '이 값은 말도 안 되는 값'이라는 뜻을 표현하기 위해 두루마리 휴지를 저런식으로 말도안되게 이상하게 꽂은 것으로 보면 된다.
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.