Javascript에서 같음을 비교하기
≡ 목차 (Table of Contents)
이 글은 Javascript의 최악의 모호성으로 평가받는 같음(equality)을 비교하는 것에 관한 글이다. 다만 다른 언어에 익숙하다는 전제가 있어야 이해가 가능할지도 모르겠다.
이건 왜 같지?
일단 굉장히 유명한 예제를 하나 살펴보자.
> let a = 1 > let b = '1' > a == b true
다른 언어였다면 a
와 b
가 같다는 것이 참(true)이 되었다는 논리 전개에 파멸과 혼동을 느꼈을지도 모른다. 참 어이없는 식이다. 사실 이 정도면 컴파일 에러와 같은 문법 오류로 실행 조차 못 시키는 수준의 내용일테니까 말이다.
하지만 Javascript에서는 당연한 이야기고 이미 익숙한 이들에겐 한숨나오는 이야기일지도 모르겠다.
동일 여부 판단
사실 Javascript에는 같은지 비교하기 위한 연산자로 ==
과 함께 ===
도 있다. 즉 equal이 3개나 붙은 연산자다.
> let a = 1 > let b = '1' > a == b true > a === b false
이제 뭔가 다른게 보인다.
앞서 말했다시피 ==
와 ===
는 둘 다 같음을 비교하기 위한 오퍼레이터다.
하지만 결과에 차이가 있다면 뭔가 다른게 있는 것이다. 추론하자면 ==
는 값(value)을 비교하기 위한 오퍼레이터 같다. 아니 정확하게 값을 비교하는 것도 아니고 비슷한 값인지 비교를 한다. 다른 말로 느슨한 비교라고도 할 수 있다.
반면 ===
는 빡빡한 비교 연산자인데 대충 설명하자면 값과 함께 타입(types)과 레퍼런스(references)도 비교한다고 볼 수 있다.
같다라는 의미의 오퍼레이터가 있다면 같지 않다라는 것도 있을 것이다. 당연하게도 NOT(!)을 붙이면 되겠지라고 생각한다면 정답이다. 같지 않다라는 의미로 !=
와 !==
가 있고, 느슨하게 비교하나 빡빡하게 비교하나의 차이도 동일하다.
모호성의 폭증
안타깝게도 앞의 예를 모든 곳에서 써먹을 수 있는 것은 아니다.
> let a = {age: 18} > let b = {age: 18} > a == b false > a === b false
Javascript도 레퍼런스 변수 시스템을 사용하는 언어라는 점을 안다면 당연한 이야기일 것이다.
즉 ==
는 여기서는 객체의 레퍼런스를 비교한다. 그리고 a
와 b
는 다른 레퍼런스로 만들어졌으니 둘은 다르다. 거기다 ===
로 비교해도 이번에는 다를 수 밖에 없다. 레퍼런스가 다르니까.
그래서 아래와 같이 레퍼런스 대입을 사용하면 또 다른 결과를 볼 수 있다.
> b = a > a == b true > a === b true
그러니까 왜 당연한 이야기를 하냐고? 앞에서 봤던 예를 다시 꺼내기 위함이다.
> 2 == '2' true > new String('33') == 33 true
Javascript의 문자열도 분명 String
이라는 클래스의 객체다. 그렇다면 레퍼런스로 비교되어야 맞는 것 같다. 그런데 왜 값을 비교하고 있는 걸까?
이건 함정이다. 이상한 함정에 빠졌다.
왜냐하면 자바스크립트의 문자열은 원시 타입(Primitive Type)이면서도 메서드를 가지는 초월적인 존재이기 때문이다. 이게 다 자바스크립트 탓이다. 참고로 이 글은 자바스크립트를 정중하게 욕하는 글이다.
우리는 무엇을 써야하나
사실 추천할 답은 이미 정해져 있다.
> null == undefined true > null === undefined false > true == 1 true > true === 1 false > true == '1' true > true === '1' false
느슨한 비교가 얼마나 착오를 만들어내는 지는 매우 유명하다. 따라서 우리가 자주 사용해야 할 것은 빡빡한 비교 연산자인 ===
과 !==
이다. 이 둘은 적어도 ==
, !=
보다 부작용이 심하진 않다.
안타깝지만 이것은 Javascript의 특징임을 인정하고 공부를 시작하는 수밖에 없다고 보인다.