Front-End/JavaScript

[You Don't Know JS] #06 자바스크립트의 강제변환(1) (자동 타입변환 / Type Conversion)

koh1018 2022. 4. 6. 17:33
반응형

 

 

/* 이 글은 카일 심슨의 You Don't Know JS를 읽으며 배운 것들을 개인적으로 정리하고 기록하기 위한 글입니다. */

 

 

 

자바스크립트의 강제변환이 유용한 기능인지, 언어 설계상 결함인지는 처음부터 큰 논란거리였다.

여기서는 강제변환의 좋고 나쁨을 충분히 이해하고 자신의 프로그램에 적절한지 스스로 현명하게 판단할 수 있는 역량을 갖추어 보겠다.

 

어떤 값을 다른 타입의 값으로 바꾸는 과정이 명시적이면 '타입 캐스팅(Type Casting)', 값이 사용되는 규칙에 따라 암시적이면 '강제변환(Coercion)'이라고 한다.

 

자바스크립트에서는 대부분 모든 유형의 타입변환을 강제변환으로 뭉뚱그려 일컫는 경향이 있어 '암시적 강제변환(Explicit Coercion)''명시적 강제변환(Implicit Coercion)' 두 가지로 구별하겠다.

 

  • 명시적 강제변환 : 코드만 봐도 의도적으로 타입변환을 일으킨다는 사실이 명백함
  • 암시적 강제변환 : 다른 작업 도중 불분명한 부수 효과(Side Effect)로부터 발생하는 타입변환
var a = 42;
var b = a + "";	// 암시적 강제변환
var c = String(a);	// 명시적 강제변환

 

 

 


 

 

자바스크립트에서는 1과 0은 true, false에 해당되지 않는다.

자바스크립트에서 숫자는 숫자고 불리언은 불리언으로 서로 별개이다.

 

만약 true/false가 아닌 값을 불리언에 상당한 값으로 강제변환했을 때, 이 값들은 어떻게 작동할까?

 

불리언으로 강제변환 시 false가 되는 몇 개 안되는 특별한 값들은 이미 자바스크립트 명세에 정의되어 있다. (Falsy 값)

  • undefined
  • null
  • false
  • +0, -0, NaN
  • ""

위 목록에 있는 것들이 'falsy' 값이며 불리언으로 강제변환하면 false가 되는 유일한 값들이다.

이외의 값들은 모두 'truthy' 값이며(사실 자바스크립트 명세에 'truthy'값 목록 같은 건 없다) true로 변환된다.

 

 

 


 

 

명시적 강제변환

분명하고 확실한 타입변환이다.

 

- 문자열 ↔ 숫자

가장 간단하면서 잦은 강제변환이라고 할 수 있는 것이 '문자열 ↔ 숫자' 강제변환이다.

'문자열 ↔ 숫자' 강제변환은 String()과 Number() 함수를 이용하는데, 앞에 new 키워드가 붙지 않기 때문에 객체 래퍼를 생성하는 것이 아니다.

var a = 42;
var b = String(a);

var c = "3.14";
var d = Number(c);

b;	// "42"
d;	// 3.14

ToString 추상 연산 로직에 따라 String()은 값을 받아 원시 문자열로 강제변환한다.

Number() 역시 마찬가지로 ToNumber 추상 연산 로직에 의해 어떤 값이든 원시 숫자 값으로 강제변환한다.

이는 누가 봐도 타입변환이 일어난다는 사실은 의심의 여지가 없기에 '명시적 강제변환'이 맞다.

 

var a = 42;
var b = a.toString();

var c = "3.14";
var d = +c;

b;	// "42"
d;	// 3.14

그럼 위 예제는 어떨까?

a.toString() 호출은 겉보기엔 명시적이지만 암시적인 요소가 감춰져있다.

원시 값 42에는 toString() 메서드가 없으므로 엔진은 자동으로 42를 객체 래퍼로 '박싱'하고 toString()을 사용할 수 있게 해준다. 그래서 어떻게 보면 '명시적으로, 암시적인' 작동이라고 할 수 있다.

 

+c의 +는 단항 연산자(Unary Operator)다. 단항 연산자는 덧셈을 의미하는 것이 아니라 +3, -2와 같이 앞에 붙는 연산자를 의미한다.

위와 같이 +c를 하면 피연산자 c를 숫자로 명시적 강제변환한다.

하지만 이는 개발자의 경험과 시야에 따라 다를 수 있다. 단항 연산자 +가 숫자로 강제변환하는 기능이란 사실을 알고 있다면 상관없지만 이 연산자를 처음 보는 사람에게는 그렇지 않을 것이기 때문이다.

(참고 : 오픈 소스 자바스크립트 커뮤니티에서는 + 단항 연산자를 명시적 강제변환 형식으로 대부분 인정하는 분위기라고 한다.)

 

- 날짜 → 숫자

위에서 본 + 단항 연산자는 'Date 객체 -> 숫자' 강제변환 용도로도 쓸 수 있다.

var d = new Date("Mon, 18 Aug 2014 08:53:06 CDT");
+d;	// 1408369986000

 

아래는 현재 시각을 타임스탬프로 바꿀 때 관용적으로 사용하는 방법이다.

var timestamp = +new Date();

(참고 : 사실 강제변환을 하지 않아도 ES5에 추가된 정적 함수 Date.now()를 쓰면 현재 시각을 타임스탬프로 얻을 수 있다.

그 외의 특정 날짜/시간의 타임 스탬프는 new Date().getTime()을 사용하는 것이 좋다.)

 

- 숫자 형태의 문자열 파싱

문자열에 포함된 숫자를 파싱하는 것은 '문자열 → 숫자' 강제변환과 결과는 비슷하지만 앞서 배운 타입변환과는 분명한 차이가 있다.

var a = "42";
var b = "42px";

Number(a);  // 42
parseInt(a);  // 42

Number(b);  // NaN
parseInt(b);  // 42

 

 

  • 강제변환(Number()) : 비 숫자형 문자를 허용하지 않음. NaN을 반환함.
  • 문자열 → 숫자 값 파싱(parseInt()) : 비 숫자형 문자를 허용. (좌→우 방향으로 파싱하다가 숫자 같지 않은 문자를 만나면 즉시 멈춤)

비슷해보일 수 있으나 파싱은 강제변환의 대안이 될 수 없다. 목적 자체가 다르다.

반드시 숫자여야만 하고 비 숫자형 문자가 들어오는 경우 되돌려야 한다면 강제변환을 사용해야한다.

만약 우측에 비 숫자형 문자가 있을지 확실하지 않거나 크게 상관 없다면 파싱 하면 된다.

 

 

 

암시적 변환

암시적 강제변환은 부수 효과가 명확하지 않게 숨겨진 형태로 일어나는 타입변환이다.

즉, 보기에 분명하지 않은 타입변환은 모두 이 범주에 속한다.

자바스크립트의 강제변환을 향한 대부분의 불만은 바로 이 암시적 강제변환을 겨냥하고 있다.

 

하지만 작가는 이 암시적 강제변환이 무엇이고 어떻게 활용할 지에 대해, 대부분의 부정적인 관점과는 조금 다른 관점에서 이야기를 펼친다.

 

 

Continue ...

반응형