자주 들르는 커뮤니티에서 자바스크립트의 형변환으로 인한 여러 사례로 재미있는 글이 올라온 걸 봤습니다. 비슷한 문제로 생각지 못한 엉뚱한 곳에서 발생하는 문제를 종종 경험했기에 충분히 이해도 됩니다. 그 이상한 일들이 왜 일어나는지에 대해 이 글을 통해 정리 해 보려 합니다.
목차
자바스크립트 동등 비교연산
console.log(0 == "0"); // true console.log(0 == []); // true // "0" == 0 == [] 이라면? console.log("0" == []); // false
0 == “0” 이 true이고 0 == [] 도 true라면 “0” == [] 가 true가 아닐까? 하지만 결과는 false 입니다. 어찌 된 일일까요?
자바스크립트에서는 동등 비교연산(== 또는 !=)을 수행 할 때, 두 피연산자의 타입이 다른 경우 두 피연산자를 동일한 타입으로 변환 후 비교연산을 수행합니다.
타입 변환에 대한 규칙은 다음과 같습니다.
- 숫자와 문자열 비교 시 문자열을 숫자로 변환
- 숫자 또는 문자열과 객체 비교 시 객체를 기본 데이터 타입으로 변환
여러가지 타입 변환에 대한 규칙이 있지만 이번 문제에 적용되는 규칙은 위의 두 가지 입니다. (ECMAScript Language Specification – Abstract Equality Comparison Algorithm)
이 규칙을 알고 다시 한번 풀어서 비교 해 보겠습니다.
// 1. 숫자와 문자열 비교는 문자열을 숫자로 변환 // console.log(0 == "0"); // true console.log(Number("0")); // 0 console.log(0 == Number("0")); // 0 == 0 의 결과 true // 2. 숫자와 객체 비교는 객체를 기본 데이터 타입으로 변환 // console.log(0 == []); // true console.log(Number([])); // 0 console.log(0 == Number([])); // 0 == 0 의 결과 true // "0" == 0 == [] 이라면? // 3. 문자열과 객체 비교는 객체를 기본 데이터 타입으로 변환 // console.log("0" == []); // false console.log(String([])); // "" console.log("0" == String([])); // "0" == "" 의 결과 false
==, != 동등 연산 시 내부적으로 비교를 위해서 형변환이 이루어 집니다. 만약 형변환 없이 비교를 수행하고 싶다면 일치 연산자(===)를 사용하면 됩니다. 일치 연산자의 경우 비교되는 피연산자들의 타입이 다르면 false를 반환합니다. 일치가 아닌 불일치를 확인하고 싶다면 !== 를 사용하면 됩니다.
console.log(0 === "0"); // false console.log(0 === []); // false console.log("0" === []); // false
자바스크립트의 더하기(+) 연산자
console.log("11" + 1); // 111 console.log("11" - 1); // 10
자바스크립트는 정말 쉽고 이해하기 쉬운 언어입니다. 그런데 “11” + 1은 “111”이라는 결과가 나오고 “10” – 1은 10이라는 결과가 나옵니다. 갑자기 이해하기 어려운 언어로 변했습니다.
이런 이해하기 어려운 결과가 나오는 데는 자바스크립트에서 더하기(+) 연산자가 동작하는 방식을 이해해야 합니다. 자바스크립트에서 더하기(+) 연산자는 문자열을 연결하거나 숫자의 덧셈 연산을 합니다. (ECMAScript Language Specification – The Addition operator ( + ))
console.log("11" + 1); // 111 console.log("11" + "1"); // 111 console.log(11 + 1); // 12
더하기(+) 연산자의 피연산자가 모두 문자열이라면 문자열을 연결하는 연산을 수행합니다. “가나다라” + “마바사”인 경우에 “가나다라마바사” 결과가 나옵니다. 피연산자가 모두 숫자라면 우리가 알고 있는 덧셈 연산을 수행합니다. 1 + 1은 2의 결과가 나옵니다.
하지만 피연산자가 문자열과 숫자 또는 다른 타입의 객체가 함께 사용되는 경우에는 모두 문자열로 변환하여 문자열 연결 연산을 수행하게 됩니다.
// 1을 문자열로 변환하면 1이기 때문 같은 결과가 나온다. console.log(String(1)); // "1" console.log("11" + String(1)); // "111" console.log("11" + 1); // "111" // [1,2,3]도 문자열로 변환되면 "1,2,3" 형태가 되기에 아래 결과가 나온다. console.log(String([1,2,3])); // "1,2,3" console.log("11" + String([1,2,3])); // "111,2,3" console.log("11" + [1,2,3]); // "111,2,3" // null도 문자열로 변환하여 연산 console.log(String(null)); // "null" console.log("11" + String(null)); // "11null" console.log("11" + null); // "11null"
빼기(-) 연산자는 피연산자에 숫자 타입이 아닌 다른 타입의 객체가 있는 경우 숫자 타입으로 형변환 하여 뺄셈 연산을 수행합니다.
// "11"문자열을 숫자로 변환하여 연산 console.log(Number("11")); // 11 console.log(Number("11") - 1); // 10 console.log("11" - 1); // 10 // null도 숫자로 변환하여 연산 console.log(Number(null)); // 0 console.log(1 - Number(null)); // 1 console.log(1 - null ); // 1 // boolean 타입도 예외는 없다 console.log(Number(true)); // 1 console.log(1 - Number(true)); // 0 console.log(1 - true); // 0
이제 당황하지 마세요
이제 자바스크립트의 몇 가지 자동 형변환에 대한 동작 방식을 알게 되었습니다. 앞으로는 자동 형변환으로 인해 나오는 결과에 당황하지 않을 수 있게 되었습니다.
참 쉽죠?