기본적으로 자바스크립트에서 연산자는 c언어나 java와 크게 다를바는 없다. 따라서, 특이한 부분만 집고 넘어가도록 하자
동등 비교 ( == ) (또는 추상 동등성 비교 연산자라고 한다. )
동등 비교는 느슨한 비교를 한다. 느슨한 비교란 좌항과 우항의 피연산자를 비교할 때 먼저 암묵적 타입 변환을 통해 타입을 일치시킨 뒤 값인지 비교한다. 기본적으로 Number로 바꾼다고 생각하면 된다.
즉 다음의 예제를 보면 된다.
console.log( 5 == 5) // true
console.log( 5 == '5') // true
문자열 '5'를 암묵적 타입 변환으로 바꾸면 5가 된다. 따라서 5 == '5'는 true가 된다.
사실 이러한 예제는 귀여운(?) 수준에 불과하다. 아래의 예제를 보면 정신이 아득해진다.
'0' ==''; // false
0 == ''; // true
0 == '0'; // true
false == 'false'; // false
false == '0'; // true
false == null; // false
false == undefined; // false
기가 막힌 결과가 나오는데, 왜 이런 결과가 나올까??
어떤 변수가 있다면, 이 변수를 조건식으로 볼 때 false로 볼 것인가 true로 볼 것인가를 결정하는 것이다.
가령 js에서 0은 false로 나온다.
if(0){
console.log("hello")
} // 실행되지 않음
0은 false로 바뀌기 때문이다. 그렇다면 어떤 것들이 falsy에 해당하고 truly에 해당하는 지 알아보자
기본적으로 truly는 falsy를 제외하고는 모두를 말한다. (NaN, inf 모두 truly 이다)
다음은 헷갈리는 것들이 있어서 이것도 truly구나를 정리해놓았다.
1. '0' (문자열에 값이 있으므로 truly이다.)
2. 'false' (문자열에 값이 있으므로 truly이다.)
3. []
4. {}
5. function(){}
3 , 4, 5는 모두 object이기 때문에 truly이다.
그렇다면 위의 기가막힌 예제를 다시봐보자
console.log('0' ==''); // false
console.log(0 == ''); // true
console.log(0 == '0'); // true
console.log(false == 'false'); // false
console.log(false == '0'); // true
'0' == '' 은 문자열이 서로 다르므로 틀리다.
0 == '' 은 ''가 falsy이므로 false로 바뀌고 0도 falsy이므로 false로 바뀌어 동등하다.
0 == '0' 은 문자열 '0'이 숫자로 바뀌어 0이되므로 동등하다.
false == 'false'는 문자열과 bool을 비교하는데, 문자열 'false'를 숫자로 바꾸면 안에 값이 있으므로 truly가 된다. 따라서 동등하지 않다.
false == '0' 은 숫자로 바뀌면 0이 되고 0은 falsy이다. 따라서 true이다.
그런데 이것보다 헷갈리는게 다음의 문장이다.
false == null; // false
false == undefined; // false
왜 이것들이 false인지는 헷갈린다. null도 undefiend도 falsy인데 false라고 생각하면 둘 다 같아야 하는 것이 아닌가??
그러나, js는 아주 신묘한 문법이라서 이렇다고 한다.
undefined와 null은 타입이자 값이다. 그러나 이들이 값이 있다고 보진 않는다.
이전까지에는 값들이 있는 경우들이므로 값들을 숫자로 변환한 다음 비교를 진행했다. 그러나 undefined와 null은 값이 없으므로 Number()로 변환한다고 될 일이 아닌 것이다.
따라서, false는 값인데 false와 비교할 값이 undefined , null이면 값이 없다고 생각하여 false를 뱉는 것이다.
false == null // 값이 있음 == 값이 없음 의 비교는 false라는 것이다.
이러한 원리를 이용하면 다음과 같은 로직도 가능하다.
null과 undefined가 값이 없다면 둘은 값이 없는 것끼리 비교를 하니까 true인가?
console.log(undefined == null ) // true
정말 기가막히고 코가 막히는 원리이다.
결론적으로 말하자면 '동등 연산자'는 쓰지 않는게 좋다. 뭐가 되었든 간에 값을 변형시켜 비교한다는 게 로직에 좋을 리가 없다.
동등 비교자가 값만 같았으면 되는 것과는 달리 일치 비교는 값과 타입이 모두 같아야 한다.
따라서 이제 위의 기가막힌 예제는 다음과 같은 결과나 나온다.
console.log('0' ===''); // false
console.log(0 === ''); // false
console.log(0 === '0'); // false
console.log(false === 'false'); // false
console.log(false === '0'); // false
console.log(false === null); // false
console.log(false === undefined); // false
우리가 원하는 아주 건전한 결과가 나오는 것이다.
그런데 기가막힌 예제가 하나 더 있다.
console.log(NaN === NaN) // false
무슨 말도 안되는 경우가 다 있나 싶겠지만, 사실 NaN은 존재자체가 모순적이다 (숫자가 아니지만 Number자료형 입니다.)
NaN은 자신과 일치하지 않는 유일한 값이다. 따라서 NaN인지 조사하려면 isNaN을 사용해야한다.
console.log(isNaN(NaN)) // true
console.log(isNaN('NaN')) // true
console.log(isNaN('www')) // true
console.log(isNaN(123)) // false
그러나 isNaN() 을 사용한다해서 만사 Ok는 아니다. isNaN은 Number자료형으로만 사용될 때 의미가 있다. 문자열이 들어가면 무조건 true을 반환하므로 조심하도록 하자.
typeof 연산자를 이용하면 피연산자의 데이터 타입을 문자열로 반환한다. 다만 데이터 타입에 없는 'function' 같은 것도 반환하므로, 7개의 데이터 타입만 나오겠지로 생각하면 난감한 결과를 얻게 될 것이다.
그런데 여기에도 심상치 않은 것이 있다.
console.log(typeof null) // object
정말 기가막히고 코가 막힌다. null은 null타입으로 나와야 하는데 object로 나온다. 이건 사실 js에서의 버그인데 기존 코드에 문제를 야기할까봐 아직도 안고치고 있다고 한다.
그래서 null 같은 경우는 그냥 === 을 사용하는 것이 좋다.
var temp = null;
console.log(null === temp); // true