자바스크립트의 느슨한 동등(loose equality) 연산자와 엄격한 일치(strict equality) 연산자의 차이점, 그리고 이 차이가 코드 품질에 왜 중요한지 알아봅니다.
자바스크립트에는 값을 비교할 때 사용할 수 있는 두 가지 동등 연산자가 있습니다. 바로 느슨한 동등 연산자 ==(더블 equals)와 엄격한 일치 연산자 ===(트리플 equals)입니다.
겉보기에는 거의 같아 보이지만 실제 동작은 전혀 다릅니다. 이 차이를 이해하지 못한 상태로 코드를 작성하면 예상치 못한 버그를 만나기 십상이므로, 반드시 짚고 넘어가야 할 개념입니다.
느슨한 동등 연산자(==)의 문제점
먼저 콘솔에서 아래 코드를 직접 실행해 보세요.
let a = 4 // 숫자(number)
let b = "4" // 문자열(string)
console.log(a == b) // 출력: true
분명히 하나는 숫자 타입이고 하나는 문자열 타입인데, 자바스크립트는 왜 위 비교 결과를 true라고 판단하는 걸까요?
그 이유는 느슨한 동등 연산자 ==는 두 피연산자의 타입이 다를 경우, 이를 같은 타입으로 변환한 뒤에 값을 비교하기 때문입니다.
이 과정을 타입 강제 변환(type coercion)이라고 부릅니다. 즉, 두 값을 공통 타입으로 맞춘 후에 동등성을 검사하는 것이죠.
따라서 위 예제에서 true가 출력된 것은 규칙상으로는 "맞는" 결과입니다. 비교가 이루어지기 전에 이미 값의 타입이 동일하게 변환되었기 때문입니다.
"정말 이상한 설계 아니야?"라고 생각하실 수 있습니다. 저도 동감입니다. 하지만 현실은 그렇습니다. 중요한 것은 자바스크립트의 이런 불편한 "특성(quirk)"을 정확히 인지하고 있는 것입니다.
엄격한 일치 연산자(===)가 해결책이다
바로 여기서 엄격한 일치 연산자 ===가 등장합니다. 이 연산자는 타입 변환을 수행하지 않고, 값의 타입까지 엄격하게 비교한 후 동등 여부를 판단합니다.
let a = 4
let b = "4"
console.log(a === b)
// 출력: false
이번에는 false가 출력됩니다. 두 변수(a와 b)가 모두 "4"라는 값을 담고 있지만, 피연산자의 타입이 서로 다르기 때문입니다(a는 숫자, b는 문자열).
타입을 임의로 변환하지 않는 === 연산자는 언제나 예측 가능한 결과를 반환합니다. 이것이 대부분의 개발자가 == 사용을 지양하라고 조언하는 이유입니다.
추가로 알아두면 좋은 함정 사례
느슨한 동등 연산자의 타입 강제 변환은 의외의 곳에서 버그를 만들어냅니다. 대표적인 예는 다음과 같습니다.
console.log(0 == false) // true
console.log("" == false) // true
console.log(null == undefined) // true
console.log(NaN == NaN) // false
반면 ===를 사용하면 위 비교 대부분이 false를 반환해 훨씬 직관적입니다. 참고로 null == undefined만이 유일하게 true를 반환하는 특수 규칙이며, 더욱 엄격한 비교가 필요하다면 ES6에서 도입된 Object.is() 메서드를 활용하는 것도 좋은 방법입니다.
그래도 느슨한 == 연산자를 써야 할 이유가 있을까?
드물지만, 찾아보면 활용 사례가 아예 없지는 않습니다. 다만 실무에서는 다음과 같은 원칙을 지키는 것이 좋습니다.
- 기본적으로는 항상 엄격한
===연산자를 사용한다. - 느슨한
==연산자를 사용해야 할 명확한 이유가 있을 때만 예외적으로 사용한다.
이 원칙만 지켜도 잘못된 동등 연산자 사용으로 인한 버그를 대부분 예방할 수 있으며, 이는 코드 안정성 면에서 언제나 이득입니다.