민규의 개발블로그
자바스크립트 강제변환-2 본문
암시적 변환
암시적 강제변환은 부수 효과가 명황하지 않게 숨겨진 형태로 일어나는 타입변환이다.
명시적 강제변환의 목적(코드를 명확하게, 이해할 수 있게 작성함)과는 반대라는 사실에 유해하다는 인식이 있지만
"You Don't know JS" 책에서는 다른 관점에서 설명한다.
이 책에서는 암시적 강제변환은 많은 장점이 있지만 몇 가지 단점 때문에 무조건 나쁘다라고 단정하진 말자는 주의다.
암시적 강제변환으로 지저분한 코드를 감추고 코딩에 도움이 될 수 있다.
문자열 <--> 숫자
처음 알게 된 배열 덧셈
간단히 말하면 + 연산의 한쪽 피연산자가 문자열이면(어떤 과정을 거쳐 문자열이 되면) +는 문자열 붙이기 연산을 한다.
피연산자중 하나가 객체라면, 먼저 이 값에 ToPrimitive 추상 연산을 수행하고, 다시 ToPrimitive는 number 콘텍스트 힌트를 넘겨 [[DefaultValue]] 알고리즘을 호출한다.
그래서 valueOf( )에 배열을 넘기면 단순 원시 값을 반환할 수 없으므로 바통은 toString( )으로 넘어가서 두 배열은 각각 "1,2"와 "3,4"가 되고 +는 두 문자열을 붙여 최종 "1,23,4"가 된다.
멋진 사례
a+"" 는 숫자를 문자열로 강제변환하는 흔한 관용 코드다.
명시적 강제변환 String(a)에 비해 암시적 강제변환 a+"" 가 더 깔끔해 보이지 않는가?? -- 개인적인 생각
유의 할 점은 추상 연산 과정에서 a + ""는 a 값을 valueOf( ) 메서드에 전달하여 호출하고, 그 결괏값을 추상 연산 하여 최종적인 문자열로 변환된다. 그러나 String(a)는 toString( )를 직접 호출할 뿐이다.
따라서 객체라면 결괏값이 달라질 수 있다.
암시적 강제변환 -> 불리언
불리언으로 암시적인 강제변환이 일어나는 표현식
- if ( )문의 조건 표현식
- for( ; ; )에서 두 번째 저간 펴햔ㅅ;ㄱ
- while ( )및 do while( ) 루프의 조건 표현식
- ? : 삼항 연산 시 첫 번째 조건 표현식
- || 및 &&의 좌측 피연산자
&&와 || 연산자
자바스크립트에서는 이것들을 '논리 연산자'라는 명칭보단 정확하게는 '피연산자 선택 연산자'라 볼 수도 있다.
이유는 자바스크립트에서 이 두 연산자는 다른 언어와 달리 실제로 결괏값이 논리 값이 아니기 때문이다.
결괏값은 두 피연산자 중 한쪽값이다. 즉 두 피연산자의 값들 중 하나다.
||, && 연산자는 우선 첫 번째 피연산자의 불리언 값을 평가한다. 피연산자가 비 불리언 타입이면 먼저 ToBoolean으로 강제변환 후 평가를 계속한다.
|| 연산자는 그 결과가 true면 첫 번째 피연산자 값을, false면 두 번째 피연산자값을 반환한다.
&& 연산자는 true면 두 번째 피연산자 값을, false면 첫 번째 피연산자 값을 반환한다.
따라서 if문이나 for루프는 이 결괏값들을 불리언으로 암시적 강제변환하여 돌아간다.
느슨한//엄격한 동등비교
느슨한 동등 비교는 == 연산자를, 엄격한 동등 비교는 === 연산자를 각각 사용한다.
결론 부터 말하면 동등함의 비교 시 ==는 강제변환을 허용하지만, ===는 강제변환을 허용하지 않는다.
a === b는 강제변환이 허용되지 않는 데다 10과 "10"은 누가봐도 다른 값이라 false다.
하지만 느슨한 동등 비교 a == b에서는 피연산자의 타입이 다르면, 비교 알고리즘에 의한 한쪽 또는 양쪽 피연산자 값이 알아서 암시적으로 변환된다.
- Type(x)가 Number고 Type(y)가 String이면, x == ToNumber(y) 비교 결과를 반환한다.
- Type(x)가 String이고 Type(y)가 Number이면, ToNumber(x) == y 비교 결과를 반환한다.
불리언에서 실수 하는 것이 있다.
- Type(x)가 불리언이면 ToNumber(x) == y의 비교 결과를 반환한다.
- Type(y)가 불리언이면 x == ToNumber(y)의 비교 결과를 반환한다.
위의 코드에서 b를 ToNumber 강제 변환하면 1이다. 따라서 a와는 같고 c와는 다르다.
null과 undefined는 느슨한 동등 비교하면 서로에게 타입을 맞춘다.
null <--> undefined 강제변환은 안전하고 예측 가능하며, 다른 값도 비교 결과 긍정 오류를 할 가능성이 없다.
따라서 아래의 강제변환은 권장한다.
a == null의 평가 결과는 Something( )이 null이나 undefined를 반환할 경우에만 true, 이외의 값(0,false, "" 등도 포함)이 반환되면 false다.
객체의 경우는 다음과 같다.
- Type(x)가 String 또는 Number고 Type(y)가 객체라면, x == ToPrimitive(y)의 비교 결과를 반환한다.
- Type(x)가 객체이고 Type(y)가 String 또는 Number라면, ToPrimitive(x) == y의 비교 결과를 반환한다.
원시 값을 감싼 객체 래퍼를 언박싱하여 비교한다. 그러나 undefined, null은 객체 래퍼가 따로 없으므로, NaN은 Number로 박싱되지만 ==를 만나 언박싱되면 결국 NaN == NaN이 되어 false라 예외다.
아래 표를 보면 Falsy 값 비교에 관한 희귀 사례 목록이다.
따라서 강제변환의 안전한 사용법은
- 피연산자 중 하나가 true/false일 가능성이 있으면 절대로 == 연산자를 쓰지 않는다.
- 피연산자 중 하나가 [ ], " ", 0이 될 가능성이 있으면 가급적 == 연산자를 쓰지 않는다.
두가지 원칙을 준수하며 강제변환의 함정들을 피해가면 좀 더 코드를 간결하게 할 수 있고 골치 아픈 디버깅의 늪에서 나오는데 도움이 된다.
추상 관계 비교
추상적 관계 비교 알고리즘은 비교 시 피연산자 모두 문자열일 때와 그 외의 경우, 두 가지로 나뉜다.
먼저 두 피연산자에 대해 ToPrimitive 강제변환을 실시하고, 어느 한쪽이라도 문자열이 아닐 경우 양쪽 모두 ToNumber로 강제 변환하여 비교한다.
b < c 가 false인 이유는 비교 대상이 모두 문자열 값이면, 각 문자를 단순 어휘 비교한다. 따라서 "0"은 어휘상 "1"보다 작은 값이므로 실패한다.
명시적 강제변환은 다른 타입의 값으로 변환하는 의도가 확실한 코드를 말하며 혼동의 여지를 줄이고 코드 가독성 및 유지 보수성을 높일 수 있는 장점이 있다.
암시적 강제변환은 숨겨진 로직에 의한 부수 효과가 있으며 타입변환이 처리되는 과정이 명확하지 않다.
암시적 강제변환은 변환 과정이 구체적으로 어떻게 일어나는지 명확하게 알고 사용하면 부수 효과를 누릴 수 있을 것 이다.
'Javascript' 카테고리의 다른 글
자바스크립트 스코프 (0) | 2020.11.20 |
---|---|
자바스크립트 문법 (0) | 2020.11.19 |
자바스크립트 강제변환-1 (0) | 2020.11.16 |
자바스크립트 네이티브 (0) | 2020.11.13 |
자바스크립트 값 (0) | 2020.11.12 |