동등비고 : 문자열 -> 숫자
== 강제변환 예제를 살펴보자.
var a = 42;
var b = "42";
a === b; // false
a == b; // true
예상대로 a === b
는 false다. 강제변환이 허용되지 않는 데다 42와 "42"는 그냥 봐도 다른 값이기 때문이다.
하지만 느슨한 동등 비교 a == b
에서는 피연산자의 타입이 다르면, 비교 알고리즘에 의해 한쪽 또는 양쪽 피연산자 값이 알아서 암시적으로 강제변환 된다.
그런데 정확히 어떻게 강제변환이 일어나는 걸까? 42가 문자열로 바뀌어 a가 되는 걸까 아니면 "42"가 숫자로 바뀌어 b가 되는 걸까?
ES5 11.9.3.4-5 원문을 보면
- Type(x)가 Number고 Type(y)가 String이면, x == ToNumber(y) 비교 결과를 반환한다.
- Type(x)가 String고 Type(y)가 Number이면, ToNumber(x) == y 비교 결과를 반환한다.
명세를 보니 비교 전 먼저 "42" 값이 숫자로 강제변환 된다는 것을 분명히 알 수 있다. 강제변환은 이미 앞서 설명했던 ToNumber 추상 연산이 담당하고 결괏값은 42이므로 두 42는 명백히 동등하다.
동등비교 * -> 불리언
어던 값을 true/false와 직접 비교하려고 하면 느슨한 동등비교의 숨겨진, 가장 끔찍한 강제변환 함정에 빠지게 될 것이다.
var a = "42";
var b = true;
a == b; // false
잠깐 이게뭐지? "42"는 truthy 값이니 == 비교하면 true 아닌가? 겨로가가 반대인 이유는 단순하면서도 꽤 까다롭다. 참으로 오해하기 쉬운 문제인데 많은 개발자가 관심을 갖고 제대로 이해하려고 하지 않는다.
ES5 11.9.3.6-7를 살펴보면
- Type(x)이 불리언이면 ToNumbe(x) == y의 비교 결과를 반환한다.
- Type(y)이 불리언이면 x == ToNumber(y)의 비교 결과를 반환한다.
자, 다음의 코드를 보자.
var x = true;
var y = "42";
x == y; // false
Type(x)
은 불리언이므로 ToNumber(x) -> 1
로 강제변환 된다. 다라서 1 == "42"
이 되는데 타입이 상이하므로 알고리즘을 수행한다. 결국 "42"는 42로 바뀌어 1 == 42 --> false
가 된다.
x, y 순서를 바꾸어도 결과는 같다.
var x = "42";
var y = true;
x == y; // false
이번에는 Type(y)
가 불리언이므로 ToNumber(y)
는 0이고 "42" == 0 ---> (재귀적으로)42 == 0 ---> false
다.
결론적으로 "42"는 == true도, == false도 아니다. 언뜻보면 말도 안되는 소리다. 어떻게 truthy도 falsy도 아닌 값이 있단 말인가?
하지만 바로 이게 문제다. 우리는 지금 완전히 틀린 질문을 하고 있다. "42"는 분명 truthy
값이지만 "42" == true
는 우리의 두뇌가 어떻게 반응하든 상관없이 불리언 평가나 강제변환을 전혀 하지 않는다. "42"가 불리언으로 강제변환 되는 것이 아니라 도리어 true가 1로 강제변환 되고 그 후 "42"가 42로 강제변환 된다.
이런 방식이 맘에 들지 않더라도 어쨌든 ToBoolean
은 전혀 개입하지 않으며, "42" 값 자체의 truthy/falsy 여부는 == 연산과는 전혀 무관하다.
==의 비교 알고리즘이 각 타입 조합별로 어떻게 작동하는가가 중요하다. 아까도 보았지만 ==의 피연산자 한쪽이 불리언 값이면 예외 없이 그 값이 먼저 숫자로 강제변환 된다.
나만 이상한건가 싶다면, 절대 그렇지 않다. 어떠한 일이 있더라고, 절대로, 두 번 다시 == true
, == false
같은 코드는 쓰지 말라고 개인적으로 강권하고 싶다.
하지만 쓰지 말라고 한 연산자는 ==이지, ===이 아니다. === true
. === false
는 강제변환을 허용하지 않기에 ToNumber
강제변환 따위는 신경 쓰지 않아도 된다.
var a = "42";
// 실패한다
if (a == true) {
// ...
}
// 이것도 실패
if (a === true) {
// ...
}
// 암시적으로 작동
if (a) {
// ...
}
// 명시적으로 작동
if (!!a) {
// ...
}
// 명시적으로 작동
if (Boolean(a)) {
// ...
}
그냥 앞으로 == true
, == false
같은 코드를 안쓰면 윌는 골치 아픈 truthy
/falsy
문제에서 해방될 것이다.
참고
- You Don't Know JS - 타입과 문법, 스코프와 클로저( 한빛 미디어 )
'JAVASCRIPT' 카테고리의 다른 글
[JS][강제변환] 동등비교 : 희귀 사례 (1) (0) | 2022.02.12 |
---|---|
[JS][강제변환] 동등비교 : null -> undefined, 객체 -> 비객체 (0) | 2022.02.12 |
[JS][강제변환] 느슨한/엄격한 동등 비교 ( ==, ===) (0) | 2022.02.12 |
[JS][강제변환] 암시적 강제변환 : * -> 불리언, || 와 && 연산자 (0) | 2022.02.11 |
[JS][강제변환] 암시적 강제변환 : 불리언 -> 숫자 (0) | 2022.02.11 |
댓글