콘텐츠로 건너뛰기

개발자를 당황하게 만드는 자바스크립트 형변환

자주 들르는 커뮤니티에서 자바스크립트의 형변환으로 인한 여러 사례로 재미있는 글이 올라온 걸 봤습니다. 비슷한 문제로 생각지 못한 엉뚱한 곳에서 발생하는 문제를 종종 경험했기에 충분히 이해도 됩니다. 그 이상한 일들이 왜 일어나는지에 대해 이 글을 통해 정리 해 보려 합니다.

자바스크립트 동등 비교연산

자바스크립트의 자동 형변환을 이해 해야 당황하지 않음
자바스크립트의 자동 형변환을 이해 해야 당황하지 않음
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
console.log(0 == "0"); // true
console.log(0 == []); // true
// "0" == 0 == [] 이라면?
console.log("0" == []); // false
console.log(0 == "0"); // true console.log(0 == []); // true // "0" == 0 == [] 이라면? console.log("0" == []); // false
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)

이 규칙을 알고 다시 한번 풀어서 비교 해 보겠습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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
// 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
// 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를 반환합니다. 일치가 아닌 불일치를 확인하고 싶다면 !== 를 사용하면 됩니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
console.log(0 === "0"); // false
console.log(0 === []); // false
console.log("0" === []); // false
console.log(0 === "0"); // false console.log(0 === []); // false console.log("0" === []); // false
console.log(0 === "0");     // false
console.log(0 === []);      // false
console.log("0" === []);    // false

자바스크립트의 더하기(+) 연산자

쉽고 이해하기 쉬운 자바스크립트
쉽고 이해하기 쉬운 자바스크립트
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
console.log("11" + 1); // 111
console.log("11" - 1); // 10
console.log("11" + 1); // 111 console.log("11" - 1); // 10
console.log("11" + 1);     // 111
console.log("11" - 1);     // 10

자바스크립트는 정말 쉽고 이해하기 쉬운 언어입니다. 그런데 “11” + 1은 “111”이라는 결과가 나오고 “10” – 1은 10이라는 결과가 나옵니다. 갑자기 이해하기 어려운 언어로 변했습니다.

이런 이해하기 어려운 결과가 나오는 데는 자바스크립트에서 더하기(+) 연산자가 동작하는 방식을 이해해야 합니다. 자바스크립트에서 더하기(+) 연산자는 문자열을 연결하거나 숫자의 덧셈 연산을 합니다. (ECMAScript Language Specification – The Addition operator ( + ))

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
console.log("11" + 1); // 111
console.log("11" + "1"); // 111
console.log(11 + 1); // 12
console.log("11" + 1); // 111 console.log("11" + "1"); // 111 console.log(11 + 1); // 12
console.log("11" + 1);     // 111
console.log("11" + "1");   // 111
console.log(11 + 1);       // 12

더하기(+) 연산자의 피연산자가 모두 문자열이라면 문자열을 연결하는 연산을 수행합니다. “가나다라” + “마바사”인 경우에 “가나다라마바사” 결과가 나옵니다. 피연산자가 모두 숫자라면 우리가 알고 있는 덧셈 연산을 수행합니다. 1 + 1은 2의 결과가 나옵니다.

하지만 피연산자가 문자열과 숫자 또는 다른 타입의 객체가 함께 사용되는 경우에는 모두 문자열로 변환하여 문자열 연결 연산을 수행하게 됩니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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"
// 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"
// 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"

빼기(-) 연산자는 피연산자에 숫자 타입이 아닌 다른 타입의 객체가 있는 경우 숫자 타입으로 형변환 하여 뺄셈 연산을 수행합니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// "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
// "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
// "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

이제 당황하지 마세요

자바스크립트 참 쉽죠?
자바스크립트 참 쉽죠?

이제 자바스크립트의 몇 가지 자동 형변환에 대한 동작 방식을 알게 되었습니다. 앞으로는 자동 형변환으로 인해 나오는 결과에 당황하지 않을 수 있게 되었습니다.

참 쉽죠?


답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다