Javascript에서 같음을 비교하기

2020년 7월 2일 수정

이 글은 Javascript의 최악의 모호성으로 평가받는 같음(equality)을 비교하는 것에 관한 글이다. 다만 다른 언어에 익숙하다는 전제가 있어야 이해가 가능할지도 모르겠다.

이건 왜 같지?

일단 굉장히 유명한 예제를 하나 살펴보자.

> let a = 1
> let b = '1'
> a == b
true

다른 언어였다면 ab 가 같다는 것이 참(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도 레퍼런스 변수 시스템을 사용하는 언어라는 점을 안다면 당연한 이야기일 것이다.

== 는 여기서는 객체의 레퍼런스를 비교한다. 그리고 ab 는 다른 레퍼런스로 만들어졌으니 둘은 다르다. 거기다 === 로 비교해도 이번에는 다를 수 밖에 없다. 레퍼런스가 다르니까.

그래서 아래와 같이 레퍼런스 대입을 사용하면 또 다른 결과를 볼 수 있다.

> 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의 특징임을 인정하고 공부를 시작하는 수밖에 없다고 보인다.