what you need to know about javascripts implicit coercion - Lee-hyuna/33-js-concepts-kr GitHub Wiki
μλ¬Έ: What you need to know about Javascript's 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
ν¨μλ₯Ό νΈμΆνλ κ²κ³Ό μ μ¬νλ€. μ΄κ²μ λ§€μ° κ°λ¨νλ€. μ«μλ§ ν¬ν¨νλ λ¬Έμμ΄μ μ«μλ§νΌ λ³νλμ§λ§, μ«μκ° μλ λ¬Έμλ₯Ό ν¬ν¨νλ λ¬Έμμ΄μ 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("one") // NaN
Number("text") // NaN
+
μ°μ°μλ λ€λ₯Έ μν μ°μ°μμ λ€λ₯΄κ² λκ°μ§μ κΈ°λ₯μ μννλ€.
- μνμ λ§μ
- λ¬Έμμ΄μ μ°κ²°(concatenation)
λ¬Έμμ΄μ΄ + μ°μ°μμ νΌμ°μ°μμΌ κ²½μ°, μλ°μ€ν¬λ¦½νΈλ λ¬Έμμ΄μ μ«μλ‘ λ³ννλ λμ μ«μλ₯Ό λ¬Έμμ΄λ‘ λ³ννλ€.
// λ¬Έμμ΄λ‘ μ°κ²°
1 + "2" // "12"
1 + "js" // "1js"
// λ§μ
1 + 2 // 3
1 + 2 + 1 // 4
// λ§μ
ν μ°κ²°
1 + 2 + "1" // "31"
(1 + 2) + "1" // "31"
// λͺ¨λ μ°κ²°
1 + "2" + 1 // "121"
(1 + "2") + 1 // "121"
λλΆλΆμ μλ°μ€ν¬λ¦½νΈμ Object λ³νμ λκ² [object Object]
λ‘ λ³νλλ€. μμλ₯Ό 보μ.
"name" + {} // "name[object Object]
λͺ¨λ μλ°μ€ν¬λ¦½νΈ Objectλ toString
λ©μλλ₯Ό μμ λ°κΈ° λλ¬Έμ Objectκ° StringμΌλ‘ ν λ³νμ΄ κ°λ₯νλ€. toString
λ©μλλ‘ λ°νλ κ°μ λ¬Έμμ΄ μ°κ²°, μνμ κ³μ°κ³Ό κ°μ μμ
μ μ¬μ©λλ€.
const foo = {}
foo.toString() // [object Object]
const baz = {
toString: () => "I'm object baz" // toStringμ μ¬μ μ
}
baz + "!" // "I'm object baz!" (toStringμ΄ νΈμΆλμ΄ λ¬Έμμ΄ μ°κ²°)
μνμ ννμμΌ λ μλ°μ€ν¬λ¦½λ toString
μ λ°ν κ°μ μ«μλ‘ λ³ννλ €κ³ νλ€.
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
λ©μλλ Objectμ λμμ΄ μ½κ° λ€λ₯΄λ€. λ°°μ΄μ 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 ([].toString => '', Number('') => 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"
toString
λ©μλ μ΄μΈμλ μλ°μ€ν¬λ¦½νΈκ° Objectκ° λ¬Έμμ΄μ΄λ μ«μ κ°μΌλ‘ λ°ν λκΈ°λ₯Ό κΈ°λν λ μ¬μ©λλ valueOf
λ©μλλ μ μ ν μ μλ€.
valueOf() λ©μλλ νΉμ κ°μ²΄μ μμ κ°μ λ°ννλ€.
const foo = {
valueOf: () => 3
}
3 + foo // 6
3 * foo // 9
toString
κ³Ό valueOf
λ©μλκ° λͺ¨λ Objectμ μ μλ κ²½μ° μλ°μ€ν¬λ¦½νΈλ valueOf
λ©μλλ₯Ό μ¬μ©νλ€.
const bar = {
toString: () => 2,
valueOf: () => 5
}
"sa" + bar // "sa5"
3 * bar // 15
2 + bar // 7
valueOf
λ©μλλ μ«μ κ°μ λνλ΄μΌ νλ Objectλ₯Ό μν΄ λ§λ€μ΄μ‘λ€.
const two = new Number(2)
two.valueOf() // 2
λͺ¨λ μλ°μ€ν¬λ¦½νΈ κ°μ μ°Έ(true) λλ κ±°μ§(false)μΌλ‘ ν λ³νλ μ μλ€. boolean true
μ λν ν λ³νμ κ°μ΄ trutyλΌλ κ²μ μλ―Ένλ€. boolean false
μ λν νλ³νλ falsyμ΄λΌλ κ²μ μλ―Ένλ€.
μλ°μ€ν¬λ¦½νΈμλ falsy κ°μ λ°ννλ κ°λ€μ΄ μ‘΄μ¬νλ€.
- false
- 0
- null
- undefined
- ""
- NaN
- -0
μ΄ μΈμ λλ¨Έμ§ κ°λ€μ truthy κ°μ λ°ννλ€.
if (-1) // truthy
if ("0") // truthy
if ({}) // truthy
μμ μμλ€μ μ μ ν΄ λ³΄μΈλ€. κ·Έλ¬λ κ°μ μ§μ€μ±μ κ²°μ νλ €κ³ ν λ μ’ λ λͺ μμ μΌλ‘ μ¬μ©νλ κ²μ΄ μ’λ€. κΈ°λ³Έμ μΌλ‘ μλ°μ€ν¬λ¦½νΈμ μμμ νλ³νμ μμ‘΄νλ©΄ μλλ€. λΉλ‘ μμμ νλ³νμ μ λλ‘ μκ³ μλ€κ³ μκ°ν΄λ λ§μ΄λ€. μλμ κ°μ΄ μ¬μ©νμ.
const counter = 2
if (counter)
μλμ μμλ€μ μ§μ€μ±μ νλ¨νλ €κ³ ν λ μ’λ λͺ νν λ°©λ²λ€μ΄λ€.
if (counter === 2)
//or
if (typeof counter === "number")
μλ₯Όλ€μ΄ μ«μλ₯Ό 맀κ°λ³μλ‘ λ°λ ν¨μλ₯Ό μμ±νλ€κ³ κ°μ ν΄ λ³΄μ.
const add = (number) => {
if (!number) new Error("Only accepts arguments of type: number")
//your code
}
μ, μ΄μ add ν¨μλ₯Ό 0κ³Ό ν¨κ» νΈμΆνλ€λ©΄(add(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
μ μλ°μ€ν¬λ¦½νΈμμ μκΈ° μμ κ³Ό κ°μ§ μμ μ μΌν κ°μ΄λ€. λ°λΌμ NaN
μ κ·Έ μ체μ λΉκ΅νμ¬ νμΈν μ μλ€.
if (notANumber !== notANumber) // true
ES6μμ 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