쾌락코딩

javascript 의 == vs ===

|

javascript를 공부해 보았다면 아마 한 번 쯤은 이런말을 들어 보았을 것이다.

자바스크립트에서는 == 를 쓰면 안되고 === 로 비교해야 됨!

뭐 나름대로 코딩하면서 이 말을 잘 지켜온 것 같다. 말은 잘 들으니까! 처음 js 기본서를 보며 공부할 당시, 분명 이 글에 대한 설명이 있었을텐데 잘 이해가 가지 않았었고, 이해 안가는 것을 낑낑 끌어안고 있기에는 더 배워야 할 문법들이 산더미 처럼 쌓여 있었기 때문에 미루고 미루다 보니 지금 까지 와버렸다는, 누가 봐도 핑계인 핑계를 대며 위로해 보다가 이제야 문득 이런 생각이 들었다. 그럼 == 는 왜 만든거야? 왜 괜히 초보자 혼란스럽게? ==와 ===는 동작 방식이 어떻게 다르길래? 그래서 한번 알아본 것을 정리해 보았다.

=== a.k.a 일치연산자, 엄격한 같음

=== 는 두 단계의 일치를 확인한다. 첫 번째로 타입(형) 검사, 두 번째로 내용물 검사. 아주 쉬운 예시로 이해해보자.

(1) console.log(1 === 1); // true
(2) console.log(1 === '1'); // false

우선 피연산자들의 타입(형)을 확인한다. 두 피연산자의 타입이 서로 다르면 내용물 검사를 할 필요도 없이 탈락(false)이다. 그러나 (1)의 예시는 두 피연산자 모두 기본형 타입 Number으로 우선 1차 검사는 통과했다. 두 번째로 내용물 검사를 실시하자. 두 피연산자 모두 내용물이 1으로 동일하다. 끝! 따라서 엄격하게 1 과 1은 같은 것이다!

이번엔 (2)를 보자. 너무 쉽게 예상 가능하다. 1차 검사인 타입(형)검사에서 탈락이다. 하나는 Number이고 하나는 string 이므로 엄격하게 1과 ‘1’은 false이다.

또다른 예시를 보자.

const a = {"1":"hello world"};
const b = {"1":"hello world"}
console.log(a === b); // false;

오호라! 이번엔 기본형(number,string,boolean etc)끼리의 비교가 아닌 참조형([],{})끼리의 비교다! 어디 한번 위에서 사용 했던 방법을 그대로 적용 시켜보자(일단 틀릴거니까 오해없길 바란다) . 1단계, 타입(형) 비교니까… 둘다 [ ]이 아닌 { }니까 타입은 일치 맞겠지? 맞다 치고 2단계 내용물 검사로 넘어 가볼까? 내용물이 둘다 {“1”:”hello world”} 잖아? 그럼 결과는 true군! 그러나 예고했듯이 틀린 답이다. 왜 틀렸을까? 참조형 비교는 기본형 비교와는 조금 다른 점이 있다. === 연산은 참조형을 비교할 때 레퍼런스(주소 값)을 비교한다. 즉, 예제의 a와 b는 겉으로 볼 떄 내용물이 같아 보이긴 하지만 사실은 서로 다른 메모리의 주소를 가지고 있는(a가 변경되어도 b에 전혀 영향을 미치지 않는) 상황이기 때문에 엄격하게 서로 같지 않다는 것이다! 조금 확실하게 하기 위해 아래의 예제를 보자.

const a = {"1":"hello world"};
const b = a;
console.log(a == b); // true

이렇게 된다면 a와 b는 정확히 서로 같은 주소값을 가리키고 있다. 즉, a[“2”] = “whyJ!”; 라는 명령어를 실행한다면, b객체에도 마찬가지로 b[“2”] = “whyJ!”가 적용 된다는 것이다. 엄격하게 두 변수는 동일하다!

== 동등 연산자, 느슨한 같음

== 는 뭔가… 잘 쓰이지 않으면서 아주 조금 더 복잡한 면이 있다. 결과 부터 말하자면 == 연산자를 사용하면 내부적으로 ===가 추가되는 과정이 추가되는데, 개인적인 생각으로는 애초에 그냥 === 를 쓰면 되고 이해도 쉬우니까 == 보단 ===를 쓰라고 하는게 아닌가 하는 생각이든다.

그럼 어디서 내부적으로 ===가 추가 되는 걸까? 일단 동작 방법부터 살펴보자. ===는 1단계 에서 타입(형)검사를 하는데, 타입이 틀리면 그냥 탈락(false)이다. 그러나 ==는 기회를 한번 더 준다(만약 타입이 같다면 바로 2단계로 진행한다). 즉, 서로 비교가 가능하도록 피 연산자의 타입을 변환(number형태로)시켜버리고 그 상태에서 === 연산을 수행한다. 무슨 말인지 이해가 어렵다면 예제를 보자.

(1) console.log(1 == '1'); // true
(2) console.log(true == '1'); // true
(3) console.log('true' == '1'); // 퀴즈

(1)부터 살펴보자. 먼저 1단계, 타입이 number와 string으로 다르다. 그럼 false인가? 아니다. 기회를 한 번 더 준다. 어떻게? 서로 비교 가능하게 string을 number로 바꾼다. 그럼 오른쪽의 ‘1’은 number 타입인 1이 된다. 이제 여기서 === 연산이 실행 된다. 결국 1 === 1이고 이것은 true! 즉,

new Number(1) === new Number("1") //true

과 같다.

(2)를 살펴보자. 이건 조금 어려워 보인다. 일단 해보자! 1단계, 타입이 boolean과 string으로 다르다. 그럼 false인가? 아니다. 기회를 한 번 더 주자. 여기서 중요하다. ‘1’은 number로 바꾸면 1 이 됨을 안다. 그럼 ture는? 1 이다!

new Number(true); // 1

(다들 알고 있을거라 믿는다:D) 결국 1 === 1 연산임으로 true!

(3)를 살펴보자. 이건 조금 더 어려워 보일라나 모르겠다. 내가 이상하게 자꾸 헷갈렸던 부분이다. 너무나 쉬운데! 해보자. 1 단계, 타입이 string string으로 동일하다. 이미 서로 동일한 타입이므로 Number화 시키지 않는다. 스트링 그대로 비교하는면 되는 것이다. 2단계 === 검사를 통해 내용물을 검사하니 true와 1은 생김새가 다른 string이다. 따라서 false! 나만 낚인 문제였나..

==의 참조형([],{})은 ===와 동일하다!

결론

쉽고 깔끔하고 쿨하게 ===를 사용하자.

참고자료

Comments