타입을 받았을 때 예상 가능한 타입으로 바꿔주는것.
사용자는 지정해놓은 타입에 다른 타입을 넣을수도 있기때문에 자바스크립트 엔진은 사용자가 잘못 넣은 타입을 올바른 타입으로 변환하려고 시도한다. 이것은 자바스크립트의 주요한 기능 중 하나이며 가장 피해야 할 기능이다.
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: () => " promise is a boy :)"
}
1 + bar // "1 promise is a boy :)"
4 * [] // 0
4 * [2] // 8
4 + [2] // "42"
4 + [1, 2] // "41, 2"
4 * [1, 2] // NaN
"string" ? 4 : 1 // 4
undefined ? 4 : 1 // 1
사용자가 숫자 표현식에서 문자열(-, *, /, %
을 포함한 문자열)을 피연산자로 넘겼을 때마다 숫자의 암묵적 타입변환 프로세스는 문자열을 인자로 자바스크립트 내부에 내장된 Number
함수를 불러오는 것과 비슷하다. 숫자 문자(Numberic Characters)를 가졌다면 어떤 문자열이라도 동등한 숫자로 바뀐다. 하지만 만일 숫자가 아닌것(Non-Numeric Charaters)이 포함되어 있으면 NaN
을 리턴한다.
3 * "3" // 3 * 3
3 * Number("3") // 3 * 3
Number("5") // 5
Number("1.") // 1
Number("1.34") // 1.34
Number("0") // 0
Number("012") // 12
Number("1,") // NaN
Number("1+1") // NaN
Number("1a") // NaN
Number("la") // NaN
Number("one") // NaN
Number("text") // NaN
+
연산자는 2가지 기능을 한다.
문자열이 +
연산자의 피연산자로 주어졌을 때, 자바스크립트는 문자열을 숫자로 바꾸려 하지 않고 수자를 문자로 바꾸려 한다. (문자 > 숫자)
// concatenation
1 + "2" // "12"
1 + "js" // "1js"
// addition
1 + 2 // 3
1 + 2 + 1 // 4
// addition, then concatenation
1 + 2 + "1" // "31"
(1 + 2) + "1" // "31"
// concatenation all through
1 + "2" + 1 // "121"
(1 + "2") + 1 // "121"
자바스크립트에서 객체의 대부분의 암묵적 형변환은 결과값으로 [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 // 0.5
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"
4 * [1,2,3] // NaN
배열을 어딘가로 넘길때 toString()메소드를 거치면 일어나는 일을 아래 코드로 확인해보자.
4 * [] // 0
// similar to
4 * Number([].toString())
4 * Number("")
4 * 0
-----------------------------
4 / [2] // 2
// similar to
4 / Number([2].toString())
4 / Number("2")
4 / 2
Number(true) // 1
Number(false) // 0
Number("") // 0
4 + true // 5
3 * false // 0
3 * "" // 0
3 + "" // 3
문자열이나 숫자가 올 곳에 객체를 넘길 때마다 자바스크립트 엔진에 의해 사용될 valueOf메소드를 정의하는 것도 가능하다.
const foo = {
valueOf: () => 3
}
3 + foo // 6
3 * foo // 9
객체에 toString()
과 valueOf()
메소드가 전부 정의되어 있을 때는 자바스크립트 엔진은 valueOf()
메소드를 사용한다.
const bar = {
valueOf: () => 5,
toString: () => 2
}
"lolo" + bar // "lolo5"
3 * bar // 15
2 + bar // 7
valueOf()
메소드는 객체가 어떠한 숫자값을 나타낼 때 사용하기 위해 만들어졌다.
const two = new Number(2)
two.valueOf() // 2
모든 자바스크립트 값은 true
나 false
로 변환될 수 있는 특성을 가지고 있다. true
로 강제로 형 변환은 하는 것을 truthy
, false
는 falsy
라고 한다.
falsy로 취급되는 값
1. false
2. 0
3. null
4. undefined
5. ""
6. NaN
7. -0
이 외에는 전부 truety
로 취급 된다.
if (-1){} // truety
if ("0"){} // truety
if ({}){} // truety
truety
를 이용해도 되지만 값이 참임을 명시적으로 표현해주는 것이 더 좋은 코드 작성법이다.아래 코드보다는
const counter = 2 if(counter){ //... }
다음의 코드가 더 좋은 코드 작성법 이다.
if( counter === 2) {...} // or if( typeof counter === "number") {...}
아래 함수는 number타입의 변수를 받아 실행하는 함수이다.
const add = (number) => {
if(!number) new Error("Only accepts arguments of type: number")
}
해당함수에 0을 넣으면 에러가 발생하게 된다( 조건을 타입이 number가 아닌 그냥 받은 인자 자체가 아니면 이라는 뜻으로 줬기 때문)
add(0) // Error: Only accepts arguments of type: number
// 더 직관적인 코드
const add = (number) => {
if(typeof number !== "number") new Error("Only accepts arguments of type: number")
}
add(0) // no error
NaN
은 자기 자신과도 같지 않은 특별한 숫자 값이다.
NaN === NaN // false
const notANumber = 3 * "a" // NaN
notANumber == notANumber // false
notANumber === notANumber // false
NaN
은 자바스크립트에서 유일하게 자기 자신과 같지 않은 값이다.
if (notANumber !== notANumber) {..} // true
ECMAScript 6는 NaN
을 체크하기 위한 메소드(Number.isNaN
)를 만들었다.
Number.isNaN(NaN) // true
Number.isNaN("name") // false
전역 isNaN
함수는 인자가 실제로 NaN
인지 체크하기 전에 인자로 들어온 값의 형변환을 강제로 한다.
isNaN("name") // true
isNaN("1") // false
전역 isNaN
함수는 사용하지 않는 것이 좋다. 이 함수의 동작은 다음의 코드과 비슷하다고 생각하시면 됩니다.
const coerceThenCheckNaN = (val) => {
const coercedVal = Number(val)
return coercedVal !== coercedVal ? true : false
}
coerceThenCheckNaN("1a") // true
coerceThenCheckNaN("1") // false
coerceThenCheckNaN("as") // true
coerceThenCheckNaN(NaN) // true
coerceThenCheckNaN(10) // false
참고