-
묵혔다 꺼낸 JS - 암시적 변환 (==연산자의 비교연산)JS 2021. 9. 29. 16:27
이때까지 나는 자바스크립트 코딩을 하면서 ==연산자를 사용하지 않고 쭉 ===연산자을 사용하였다.
왜 나는 ==을 사용하지 않고, ===을 사용했을까?, 둘은 무엇이 다른가?, ==의 동작되는 원리가 어떠하길레 ===과 다른 결과를 나타낼까?
이에 대한 해답을 찾아내기 위해 오늘은 ==연산자와 ===연산자의 차이점을 알아보고, 글을 적는다.
그럼 지금부터 그 이유를 알아보기 위해 먼저 ==과 ===의 비교 결과의 차이를 알아보자.
결과를 통해서 알 수 있듯, ==연산자는 우리가 생각하는 예상과는 다른 결과를 내어주었지만, ===연산자는 일반적으로 우리가 예상이 가능한 결과를 도출 하였고, 많은 사람들이 원하는 결과가 나온 것을 알 수 있다.
또한 ==은 위의 코드처럼 결과가 비교의 엄격함이 느슨한 뉘앙스를 가진 것 처럼 느껴지고, ===는 순수한 변수가 지닌 값 자체를 비교하는 엄격한 강도를 가진 뉘앙스를 지닌 것 처럼 느껴진다.
사실 이 엄격함의 기준을 예상 할 수 있는 것은 "타입"이라고 생각이 될 수 있겠지만, 사실 타입이 아니라 ==과 ===의 연산 방식에 따른 차이로 인한 결과 때문이다.
아까 === 는 순수한 값(객체는 주솟값이 같은지)을 비교한 비교한다고 하였는데, ==은 어떤 연산방식을 하기에 우리가 기대하는 결과와 다를까?
방금 본 코드를 다시 보며 설명하겠다.
a == b 를 비교하여 결과를 평가 할 때 만약 두 비교연산 중 하나가 Number 타입이라면 나머지 하나의 타입은 Number 타입인지 확인 하고 타입이 다르면 암시적 강제 변환 시킨 후 그 값을 비교하고 결과를 뱉는 과정이다.
( 0 == '0' > 0 == 0 > true )
이는 비교 대상을 반대로 두어도 비교 대상 a, b 둘 중 하나라도 Number타입이면 이렇게 작동 된다.
그렇다면 이번엔 b를 문자열이 아닌 boolean 타입으로 바꾸어 비교 해보자.
우리가 예상했던대로 나와 당연하다 생각하겠지만, 암시적 변환 관점으로 생각해보면 0이 false로 변환되는지, 아니면 false가 0으로 변환되는지 생각해 볼 필요가 있을 것이다.
변환 과정은 다음과 같다. a와 b중 하나가 boolean 타입이라면 boolean타입인 비교 대상을 Number타입으로 암시적 강제 변환 한 후 비교하여 결과를 뱉는 과정이 위의 정답이다.
( 0 == false > 0 == 0 > true )
조금 더 잔머리를 써서 이번엔 a를 문자열 '0'으로 바꾸어도 같은 결과를 나타내는지 알아보자.
으아닛, 결과가 같이 나왔다. 이번에도 변환 과정을 알아보아 왜 true라는 결과가 나오는지 알아보자.
먼저 false가 Number 0으로 변환 된 후, 이 후 0 == '0'이 되고 String '0'이 Number 0으로 변환 되어 0 == 0 을 비교하여 결과는 true가 나오게 된다.
( '0' == false > '0' == 0 > 0 == 0 > true )
그럼, 이 결과는 어떠할지 예상이 가능한가 한번 예상을 해보자.
'10' == true 인데 누가 봐도 true같다. 왜냐하면 문자열 10이 truthy의 성질을 지니므로 true == true같겠지만, 암시적 변환 후 비교하는 관점으로 다시 한번 생각해보자.- '10' == true에서 먼저 true가 Number 타입으로 변환된다. ⇒ '10' == 1
- '10' == 1에서 이번엔 String 10이 Number타입으로 변환된다. ⇒ 10 == 1
- 10 == 1을 비교하여 값의 동등한지 비교한다. ⇒ false
- 결과 false를 돌려준다.
특히 방금 알아본 결과로 booelan 타입을 비교 할 때 ==는 truthy나 falsey로 비교하지 않고, 값을 변환 후 비교하므로 == 보다는 ===로 사용하는 것이 올바른 길이다.
자, 이제 왜 == 과 ===가 다른지 이해가 되었으리라 믿는다.
원리를 이해했지만 아직 확인 하지않은 케이스들이 남아있다 예를들면 객체나 배열을 대상으로 == 비교하지 못한 것이 그 예시일 것이다.
한번 알아보자.
객체의 비교의 예시를 배열로 대신하여 원시값과 ==연산자로 비교해보자.
이전 포스팅에서 배열을 + 연산자로 더했을 때 암시적 변환 결과로 문자열로 도출 된 것이 확인 되었다.
이는 ToPrimitive를 통해서 배열의 내부 원시값을 문자열로 반환 한 뒤 비교하게 되는 것이다.- [10] == 10 에서 배열 [10]의 원시값 '10'을 받는다 ⇒ '10' == 10
- '10' == 10에서 문자열 '10'을 Number타입 10으로 변환한다 ⇒ 10 == 10
- 10 == 10을 비교한다. ⇒ true
- true의 결과를 보낸다.
이로써 객체의 경우, 원시값으로 치환 한 후 비교하게 되는 과정을 알게 되었다.
Fasley의 == 비교
falsey의 성질을 지닌 값들 끼리 ==를 비교하면 어떻게 될까?
falsey를 비교한 결과들이 모두 같다는 결과가 나왔다.
각각의 과정들을 알아보자.- a == b
- 0 == ' ' 0과 빈 문자열을 비교 시 빈문자열 ''을 Number 타입으로 바꾼다. ⇒ 0 == 0
- 0 == 0을 비교한다. ⇒ true
- true를 반환한다.
- a == c
- 0 == [ ] 0과 빈 배열을 비교 시 빈 배열의 ToPrimitive를 통해 원시값 ''으로 바꾸어 비교한다. ⇒ 0 == ' '
- 0 == ' '을 비교해 빈 문자열 ''을 Number 타입으로 바꾼다. ⇒ 0 == 0
- 0 == 0을 비교한다. ⇒ true
- true를 반환한다.
- b == c
- ' ' == [ ] 빈 문자열과 빈 배열을 비교 시 빈 배열의 ToPrimitive를 통해 원시값 ''으로 바꾸어 비교한다. ⇒ ' ' == ' '
- ' ' == ' ' 를 비교한다. ⇒ true
- true를 반환한다.
여기까지 falsey의 성질을 가진 값들의 ==연산자를 이용한 비교 과정과 결과를 설명한다.
falsey의 값을 가질 가능성이 있는 값들을 비교할 때에 위와같이 우리가 원하는 false라는 결과가 아닌 true라는 결과를 나타내므로 이를 방지하기 위해서 ===연산자를 사용하도록하자. (우리 정신건강은 소중하니까...🥺)
마지막으로 정리.
==연산자를 사용함에 주의점은 다음과 같다.- 비교 대상 중 하나라도 booelan 값인 true, false라면 ==이 아닌 ===을 사용하자.
- 비교 대상 중 falsey 성질을 가진 값을 비교할 때에는 ==이 아닌 ===을 사용하자.
'JS' 카테고리의 다른 글
묵혔다가 꺼낸 JS - 렉시컬 스코프 (0) 2021.10.08 묵혔다 꺼낸 JS - 컴파일러와 스코프 (0) 2021.10.04 묵혔다 꺼낸 JS - 암시적 변환 (+, -, &&, ||) (0) 2021.09.28 묵혔다 꺼낸 JS - Falsey, 명시적 강제 변환 (0) 2021.09.21 묵혔다 꺼낸 JS - JSON.stringify (0) 2021.09.16