이 포스팅은 https://github.com/leonardomso/33-js-concepts 에 있는 포스팅들을 번역한 것입니다. 오역이나 의역이 있을 수 있습니다. 지적해주시면 확인 후 바로 정정하겠습니다.
original source of this posting is from https://dev.to/promhize/what-you-need-to-know-about-javascripts-implicit-coercion-e23 If the original author requests deletion, it will be deleted immediately.
Translated by Jake Seo (서진규)
- https://velog.io/@jakeseo_me
- https://github.com/n00nietzsche
자바스크립트의 암묵적인 타입 변환(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: () => " 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
함수를 불러오는 것과 비슷합니다. 이것은 꽤나 직관적입니다. 숫자 문자(Numeric Characters)를 가졌다면 어떤 문자열이라도 동등한 숫자로 바뀝니다. 하지만 만일 문자열에 숫자가 아닌 것(Non-Numeric Characters)이 포함되어 있으면 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가지의 기능을 합니다.
1. 수학적인 덧셈
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
의 반환 값은 문자열 합치기(string concatenation) 혹은 수학적 표현식(mathematical expressions)과 같은 연산에서 쓰이게 됩니다.
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
4 / [2] // 2
//similar to
4 * Number([].toString())
4 * Number("")
4 * 0
//
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
메소드문자열이나 숫자가 올 곳에 객체를 넘길 때마다 자바스크립트 엔진에 의해 사용될 valueOf
메소드를 정의하는 것도 가능합니다.
const foo = {
valueOf: () => 3
}
3 + foo // 6
3 * foo // 9
객체에 toString
과 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
모든 자바스크립트 값은 ture
나 false
로 변환될 수 있는 특성을 갖고 있습니다. true
로 형변환을 강제하는 것을 truthy
라고 합니다. 또 false
로 형변환을 강제하는 것을 falsy
라고 합니다.
다음은 자바스크립트에서 반환 시에 falsy
로 취급되는 값들입니다.
1. false
2. 0
3. null
4. undefined
5. ""
6. NaN
7. -0
이 외에는 전부 truthy
로 취급됩니다.
if (-1) // truthy
if ("0") // truthy
if ({}) // truthy
위의 코드처럼 truthy
를 이용해도 괜찮습니다. 하지만 값이 참임을 명시적으로 표현해주는 것이 더 좋은 작성법입니다. 명심해야 할 것은 만일 당신이 자바스크립트의 묵시적 형변환(implicit coercion)을 완벽히 이해하더라도, 자바스크립트의 묵시적인 형변환에 의존하지 말라는 것입니다.
아래 코드 대신에
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")
// your code
}
위와 같은 경우에는 인자 값으로 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 // 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
자바스크립트에서 대부분의 암묵적 강제 형변환(implicit coercion)을 다뤄보았습니다. 읽어주셔서 감사합니다.
번역 잘보고 있습니다. 감사드립니다. 다름이 아니고 오타 하나 있는거 말씀 드리고 싶습니다.
coerceThenCheckNaN 함수에서 리턴 값 'coerce !== coercedVal ? true : false'이 'coercedVal !== coercedVal ? true : false'로 변경 되어야 할것 같습니다.