2.5 비교
⭐️ 2.5.1 같음에 대한 고찰
같다는 건 정확히 어떤 의미일까?
JS에서 같음을 비교할 때는 '정확하게' 일치하는지, '아주 유사', '교환 가능' 처럼 다양하게 해석된다. 일치 비교와 동등 비교의 차이를 알고 있어야 한다.
일치 연산자 ===
비교 대상이 정확히 같을 때 참을 반환하는 연산자라고 추측할 수 있다. === 연산자만으로는 아주 정확하게 비교할 수 없다.
원시타입 비교
NaN과 -0을 만나면 === 연산자는 거짓말을 한다. → === 연산자는 NaN이나 -0과 함께 쓰지 말자.
NaN을 비교할 때는
Number.isNaN()
-0과 비교할 때는
Object.is()
(==== 초일치 비교 연산자라고 할 수 있을 정도로 아주 정확히 비교)
객체타입 비교
일치 비교는 값의 본질이나 내용을 비교한다고 볼 수 있다. 42 === 42
는 실제 숫자인 42끼리 비교가 일어난다. 비교 대상이 객체인 경우에는 값의 본질이나 내용이 아닌 구조적 일치를 비교한다.
JS에서 객체끼리 비교할 때, 비교 연산자가 구조적 일치를 판단하지 않고, 독자성 일치를 비교한다. 객체는 참조에 의해 고정되며 참조 복사본을 사용해 할당/전달 된다. 그리고 참조(독자성)를 대상으로 일치 비교가 일어난다.
JS에서는 객체 구조가 가튼지 비교할 방법이 없다. 같은 것을 참조하는지만 비교할 수 있다. 객체 구조가 같은지 비교하려면 직접 코드를 짜야 한다.
⭐️ 2.5.2 강제 변환
강제 변환은 한 타입의 값이 다른 타입의 값으로 변하는 것을 의미한다.
동등 연산자 ==
JS 커뮤니티에서 == 동등 연산자는 설계가 부실하고 위험하며 버그가 많다고 비난한다. (JS 창시자도 연산자 설계에 실수가 있다고 한탄했다.)
== 연산자
는 === 연산자
와 유사한 방식으로 피연산자가 같은지 비교한다. 두 연산자 모두 피연산자의 타입을 비교한다. 만약 피연산자가 같은 타입이라면 ==와 ===는 완전히 동일하게 작동한다. 피연산자의 타입이 다른 경우 == 연산자는 비교 이전에 강제로 타입을 맞추는 작업을 수행한다. (=== 와 다른점)
== 연산자는 강제 변환을 먼저 실행(피연산자 타입 맞추기) → === 연산자처럼 작동
필자는 == 연산자를 느슨한 동등 비교 연산자가 아닌 강제 변환 동등 비교 연산자라고 설명하는 것이 적합하다고 생각한다.
피연잔자의 타입이 다르다. ==는 숫자형이 아닌 값("42", true)을 숫자 (42, 1)로 바꾼 뒤 비교한다. == 연산자가 숫자형 피연산자를 선호한다는 본질을 알고 있다면 "" == 0
이나 0 == false
같은 코너 케이스를 피할 수 있다.
❓==가 아닌 ===만 사용하면 되지 않을까?
비교 연산자에는 ==, <, >, <=, >=
도 있다. 나머지 연산자들 모두 피연산자들의 타입이 같으면 ===
처럼 작동한다. 다른 경우에는 타입 강제 변환이 먼저 일어난다. (대개 숫자형으로 변환)
i < arr.length
에서 i
와 arr.length
는 항상 숫자이므로 타입 강제 변환으로부터 안전하다.
arr[i] < 500
에서 arr[i]
는 항상 문자열이므로 < 연산자는 타입을 강제변환한다. 실제 비교 코드는 1 < 500, 10 < 500
이 된다. 4번째 비교에서 거짓이 반환되어 순회는 3번만 일어난다.
피연산자가 모두 문자열인경우 알파벳순으로 문자열을 비교하고, 아닌 경우 숫자 타입으로 타입을 반환해 비교를 진행한다.
비교 연산자를 사용할 때 타입 변환을 피할 방법은 피연산자의 타입을 일치시켜야 한다. 그러나 타입 강제 변환을 수반하는 비교에 대해 배우는 걸 피하기보다 비교 연산자의 작동 방식을 제대로 배우고 받아들이는 게 더 낫다.
타입 강제 변환이 수반되는 비교는 if 등의 조건문에서도 나타난다. (부록 A.3절 강제 조건부 비교)
Last updated