4. Implicit, Explicit, Nominal, Structuring and Duck Typing
- Implicit coercion(암묵적 타입 변환)
- 예상치 못한 타입을 받았을 때 예상 가능한 타입으로 바꿔주는 것 - 그로 인해 사용자는 숫자값을 넘겨야 하는 곳에 문자열을 넣을 수도 있고 문자열을 넣어야하는 곳에 객체를 넣을 수도 있다. 이러한 일이 발생했을 때 자바스크립트 엔진은 사용자가 잘못 넣은 타입을 올바른 타입으로 변환하려고 시도 => 자바스크립트의 주요 기능 중 하나이며 가장 피해야할 기능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
173 \* "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 :)"1
2
3
4
5
6
7
84 * [] // 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을 리턴.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
153 * "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가지의 기능을 한다. (loaded operator)
- 수학적인 덧셈
- 문자열 합치기
문자열이 + 연산자의 피연산자로 주어졌을 때, 자바스크립트는 문자열을 숫자로 바꾸려 하지 않고 숫자를 문자로 바꾸려 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 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]
를 반환
1
"name" + {} // "name[object Object]"
모든 자바스크립트 객체는
toString
메소드를 상속받습니다. 상속받은toString
메소드는 객체가 문자열 타입으로 변해야 할 때마다 쓰임. toString의 반환 값은 문자열 합치기(string concatenation) 혹은 수학적 표현식(mathematical expressions) 과 같은 연산에서 쓰이게 됨.1
2
3
4
5
6
7
8const foo = {}
foo.toString() // [object Object]
const baz = {
toString: () => "I'm object baz"
}
baz + "!" // "I'm object baz!"객체가 수학적 표현식 사이에 들어갔을 때는, 자바스크립트는 반환 값을 숫자로 변환하려 할 것입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const 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
4
5
6
7
8[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
메소드를 거치면 어떻게 되는지를 생각해봅시다. 숫자로 변할지 문자열로 변할지 말이죠.1
2
3
4
5
6
7
8
9
10
11
12
134 * [] // 0
4 / [2] // 2
//similar to
4 * Number([].toString())
4 * Number("")
4 * 0
//
4 / Number([2].toString())
4 / Number("2")
4 / 2- True, False, “”
1
2
3
4
5
6
7
8Number(true) // 1
Number(false) // 0
Number("") // 0
4 + true // 5
3 * false // 0
3 * "" // 0
3 + "" // 3valueOf
메소드
문자열이나 숫자가 올 곳에 객체를 넘길 때마다 자바스크립트 엔진에 의해 사용될valueOf
메소드를 정의하는 것도 가능1
2
3
4
5
6const foo = {
valueOf: () => 3
}
3 + foo // 6
3 * foo // 9객체에
toString
과valueOf
메소드가 전부 정의되어 있을 때는 자바스크립트 엔진은valueOf
메소드를 사용1
2
3
4
5
6
7
8const bar = {
valueOf: () => 5,
toString: () => 2
}
"sa" + bar // "sa5"
3 * bar // 15
2 + bar // 7valueOf
메소드는 객체가 어떠한 숫자값을 나타낼 때 사용하기 위해 만들어짐1
2
3const two = new Number(2)
two.valueOf() // 2Falsy와 Truthy : 모든 자바스크립트 값은
true
나false
로 변환될 수 있는 특성을 갖고 있음.true
로 형변환을 강제하는 것을truthy
,false
로 형변환을 강제하는 것을falsy
라고 함.- falsy로 취급되는 값들
- false
- 0
- null
- undefined
- “”
- NaN
- -0
- falsy로 취급되는 값들
이외에는 전부
truthy
1
2
3if (-1) // truthy
if ("0") // truthy
if ({}) // truthy위의 코드처럼
truthy
를 이용해도 괜찮지만 값이 참임을 명시적으로 표현해주는 것이 더 좋은 작성법. 명심해야 할 것은 자바스크립트의 묵시적인 형변환에 의존하지 말라는 것.1
2
3
4
5
6
7const counter = 2
보다
if(counter === 2)
if(counter)
보다
if(typeof counter === "number")예를 들어 아래 함수는 number 타입의 변수를 받아 실행하도록 하고 싶어 만든 함수
1
2
3
4const add = (number) => {
if(!number) new Error("Only accepts arguments of type: number")
// your code
}이 경우에 인자 값으로 0을 주면 의도치 않은 에러가 발생
1
2
3
4
5
6
7
8
9
10add(0) // Error: Only accepts arguments of type: number
// 아래처럼 명시적으로 표현해주는 것이 더 좋은 방법
const add = (number) => {
if (typeof number !== "number") new Error("Only accepts arguments of type: number")
// your code
}
add(0) // no error또한
==
이 boolean을 만나면 숫자로 변환시켜서1
2
3console.log("true" == true)
// NaN == 1
// false에서 true는 1이 되고 앞에 문자열을 숫자로 변환시키려하는데 “true”를 숫자로 변환시키려하면
NaN
이 되어서 결국 false를 반환한다.NaN :
NaN
은 자바스크립트에서 유일하게 자기 자신과도 같지 않은 특별한 숫자 값1
2
3
4
5
6NaN === NaN // false
const notANumber = 3 * "a" // NaN
notANumber == notANumber // false
notANumber === notANumber // falseES6에서는
NaN
을 체크하기 위한 메소드(Number.isNaN)를 만들었음.1
2Number.isNaN(NaN) // true
Number.isNaN("name") // false전역
isNaN
함수에 대해서도 알아둬야 함. 이 함수는 인자가 실제로 NaN인지 체크하기 전에 인자로 들어온 값의 형변환을 강제한다. 예를 들면1
2isNaN("name") // true
isNaN("1") // false전역
isNaN
함수는 사용하지 않는 것이 좋다. 이 함수의 동작은 다음의 코드과 비슷1
2
3
4
5
6
7
8
9
10const coerceThenCheckNaN = (val) => {
const coercedVal = Number(val)
return coerce !== coercedVal ? true : false
}
coerceThenCheckNaN("1a") // true
coerceThenCheckNaN("1") // false
coerceThenCheckNaN("as") // true
coerceThenCheckNaN(NaN) // true
coerceThenCheckNaN(10) // false