본문 바로가기

JavaScript

[JavaScript] 암묵적 타입 변환

암묵적 타입 변환 ( Implicit coercion )

간단하게 말하면 예상치 못한 타입을 받았을 때 예상 가능한 타입으로 바꿔준다고 생각하면 된다. 

사용자는 숫자 값을 넘겨야 하는 곳에 문자열을 넣을 수 있고, 문자열을 넣어야 하는 곳에 객체를 넣을 수 있다.

 

이런 일이 발생했을 때 자바스크립트 엔진을 사용자가 잘못 넣은 타입을 올바른 타입으로 변환하려는 시도를 한다. 

자바스크립트의 주요한 기능 중 하나이지만 가장 피해야 할 기능이다. 

 

3 * "3" // 9
1 + "2 + 1 // 121

true + true // 2
10 - true // 9

const foo = {
	valueOf: () => 2
}

3 + foo // 5
4 * foo // 8

const bar = {
	toString: () => " string";
}

1 + bar // "1 string"

4 * [] // 0
4 * [2] // 8
4 + [2] // "42"

숫자 표현식에 숫자가 아닌 값

문자열 

사용자가 숫자 표현식에서 문자열(-, *, /, % 을 포함한 문자열)을 피연사자로 넘겼을 때마다 숫자의 암묵적 타입 변환

프로세스는 문자열을 인자로 자바스크립 내부에 내장된 Number 함수를 불러오는 것과 비슷하다. 

 

 

숫자 문자를 가졌다면 어떤 문자열도 동등한 숫자로 바뀐다. 하지만 문자열에 숫자가 아닌 것이 포함되면 NaN을 리턴

3 * "3" // 3 * 3
3 * Number("3") // 3 * 3

Number("1,") // NaN

 

+ 연산자

+ 연산자는 다른 수학적 연산자들과는 다르게 2가지 기능을 한다. 

  1. 수학적인 덧셈
  2. 문자열 합치기 

문자열이 + 연산자의 피연산자로 주어졌을 때, 자바스크립트는 문자열을 숫자로 바꾸려 하지 않고 

숫자를 문자로 바꾸려 한다. 

1 + "2" // "12"
1 + "js" // "1js"

1 + 2 // 3

1 + 2 + "1" // "31"

 

객체 

자바스크립트에서 객체의 대부분의 암묵적 형변환은 결과값으로 [object Object]를 반환한다. 

"name" + {}  // "name[object Object]"

 

모든 자바스크립트 객체 toString 메서드를 상속받습니다. 상속받은 toString 메서드는 객체가 문자열 타입으로

변해야 할 때마다 쓰인다. 

 

toString의 반환 값을 문자열 합치기 혹은 수학적 표현식과 같은 연산에서 쓰이게 된다. 

const foo = {}
foo.toString() // [object Object]

const baz = {
	toString: () => "I'm object baz"
}

baz + "!" // "I'm object baz!"

 

객체가 수학적 표현식 사이에 들어갔을 때는, 자바스크립트는 반환 값을 숫자로 변환하려고 한다. 

const foo = {
	toString: () => 4
}

2 * foo // 8
2 + foo // 6
"four" + foo // four4

const baz = {
	toString:() => "four"
}

2 * baz // NaN
2 + baz // 2four

const bar = {
	toString: () => "2"
}

2 + bar // "22"
2 * bar // 4

배열 객체 

배열에 상속된 toString 메서드는 다르게 동작한다. 

배열에 아무런 인자도 넣지 않은 join 메서드를 호출한 것과 비슷한 방식으로 작동하게 된다. 

[1, 2, 3].toString()  // "1,2,3"
[1, 2, 3].join()      // "1,2,3"
[].toString()         // ""
[].join()             // ""

"me" + [1, 2, 3]      // "me1,2,3"
4 * [1, 2, 3]         // "41,2,3"

True, False 그리고 ""

Number(true)  // 1
Number(fasle) // 0
Number("")    // 0

4 + true      // 5
3 * false     // 0
3 * ""        // 0

valueOf 메서드 

문자열이나 숫자가 올 곳에 객체를 넘길 때마다 자바스크립트 엔진에 의해 사용될 valueOf 메서드를 정의할 수 있다.

const bar = {
	valueOf: () => 5,
    toString: () => 2
}

"sa" + bar // "sa5"
3 * bar    // "15
2 + bar    // 7

valueOf 메서드는 객체가 어떠한 숫자 값을 나타낼 때 사용하기 위해 만들어졌다. 

const two = new Number(2);

two.valueOf()              // 2

Falsy와 Truthy 

모든 자바스크립트 값true나 false로 변환될 수 있는 특성을 가지고 있다. 

true로 형변환을 강제하는 것을 truthy라고 하고, false로 형변환을 강제하는 것을 falsy라고 한다. 

 

자바스크립트에서 반환 시 falsy로 취급되는 값은 7가지 밖에 없다. 

  1. false
  2. 0
  3. null
  4. undefined
  5. ""
  6. NaN
  7. -0

이 외에는 전부 truthy로 취급한다. 

 

if(-1)  // truthy
if("0") // truthy
if({})  // truthy

위 코드처럼 truthy를 이용해도 전혀 문제없지만, 값이 참임을 명시적으로 표현해주는 것이 더 좋은 방법이다. 

자바스크립트의 묵시적 형변환을 완벽히 이해하더라도, 자바스크립트 묵시적인 형변환에 의존하지 말라는 것이다. 

 

const counter = 2;

if(counter)

이렇게 사용하기보단 

if(counter === 2) 

// or

if(typoof counter === "number")

좀 더 이해하기 쉬운 코드입니다. 

 

const add = (number) => {
	if(!number) new Error("Only accepts arguments of type: number")
	// your code
}

함수에서 number 타입의 변수를 받아 실행하도록 만든 함수이다. 

하지만 인자 값으로 0을 주면 의도치 않게 에러가 발생한다. 

add(0) // Error: Only accepts arguments of type: number

// better check

const add = (number) => {
	if (typeof number !== "number") new Error("Only accepts arguments of type: number")  
	// your code  
}

add(0) // no error

NaN

NaN자기 자신과도 같지 않은 특별한 숫자 값이다. 

NaN === NaN  // false

const notANumber == 3 * "a"  // NaN

notANumber == notANumber     // false
notANumber === notANumber    // false

 

ECMAScript 6는 NaN을 체크하기 위한 메서드 Number.isNaN을 만들었다. 

Number.isNaN(NaN) // true
Number.isNaN("name") // false
반응형