자바스크립트에서 값은 이상합니다.
타입을 가지고 있지 않지만 필요에 따라 타입이 변환되기도 하고, [] == 0 이 true 이고, 심지어 if([]) console.log('aa'); 도 정상적으로 동작합니다.
도대체 자바스크립트의 값은 어떻게 동작하기에 이렇게 될 수 있을까요?
[] == 0 // true
if([]) {
console.log('어, 이게 왜 되지?'); // 출력 O
}
if(0) {
console.log('어, 이게 왜 안되지?'); // 출력 X
}
모든것은 연산자에 따른 형변환의 값이 truthy, falsy 구분에 의한 현상입니다.
값의 종류
자바스크립트에는 두 가지 종류의 값이 있습니다.
하나는 Primitive Value(원시 값) 이고, 다른 하나는 Reference Value(참조 값) 입니다.
원시값에는 number, String, boolean, null, undefined가 있고,
참조값에는 array, function, object 가 있습니다.
연산자에 따른 형변환 +
자바스크립트는 연산자에 따라 형변환이 다르게 일어납니다. 또, 값이 원시값이냐 참조값이냐에 따라서도 다른 형변환이 일어납니다.
1+'1' // '11'
위 예시는 number 와 String을 + 연산했을 떄의 결과입니다. '11'의 문자열이 나왔습니다.
이 결과는 값의 형변환에 의한 결과로 볼 수 있습니다. number 1이 String 1로 변환이 되고, 두 문자열을 합친 새로운 문자열을 반환한 것으로 볼 수 있습니다.
+ 연산자는 다른 수학 연산자와 다르게 덧셈 연산 외에 두 문자열을 합치는 특별한 연산을 가지고 있습니다.
그렇다면 왜 덧셈이 아닌 두 문자열을 합치는 연산을 선택한 것일까요?
Number('alphabetString'); // NaN
Number('123'); // 123
123.toString(); // '123'
1.23.toString(); // '1.23'
'hello ' + 'world' // 'hello world'
1 + 'hello' // '1hello'
'3' + 5 // '35'
모든 문자열이 숫자로 변환될 수 있는 것은 아니지만, 모든 숫자는 문자열로 변환될 수 있기 때문입니다.
따라서 + 연산에 문자열과 숫자가 연산될 경우, 숫자를 문자열로 변환 후에 연산을 하는 것입니다.
1 + true // 2
2 + false // 0
boolean은 오직 두 가지 값을 가지고 있습니다. 다양한 종류의 문자열과는 다르게 단 두가지의 값을 가지고 있기 때문에 수샂로 형변환이 용이합니다.
true 는 1, false 는 0으로 변환하면 아주 간단합니다.
따라서 숫자와 boolean을 + 연산을 할 때는 boolean을 숫자로 변환 후에 연산을 합니다.
그렇다면, +를 제외한 다른 수학 연산자에 대해서는 어떨까요?
4 - '1' // 3
1 * '2' // 2
2 / '1' // 2
'hello' - 'ello' // NaN
-, *, / 연산자는 오직 수학적 연산을 가지고 있습니다. 즉 피연산자로 숫자만 올 수 있는 것이죠.
따라서 연산에 사용 되는 모든 값은 숫자로 변환 후에 연산을 하게 됩니다.
위 연산자 뿐만 아니라 다른 수학적 연산자 모두 동일하게 동작합니다.
이 때, 숫자로 변환될 수 없는 값은 NaN 값을 가집니다.
참조값의 형변환
자바스크립트에서의 각 연산자는 원시값을 피연산자로 가지고 있어야 합니다.
즉, 참조값은 연산에 사용할 수 없습니다.
[] + 1 // '1'
[] == 0 // true
하지만 array는 참조값인데 위의 연산이 가능한 것일까요?
그것은 바로 참조값이 자바스크립트 엔진에 의해 자동으로 원시값으로 형변환이 되었기 때문입니다.
위 예시를 보면 array 는 String으로 변환이 되는 것을 알 수 있습니다.
array 는 toString() 함수를 가지는데, 이 함수는 각 원소를 , 로 구분하여 문자열로 만드는 함수입니다.
따라서 array가 연산에 사용됐을 때 내부적으로 toString() 함수가 호출되어 array를 String으로 바꾸고 연산을 하게 됩니다.
[] + 1 => [].toString() + 1 => '' + 1 => '1'
그렇다면 Object는 어떨까요?
Object도 참조값이지만 array와 마찬가지로 연산에 사용되면 자동으로 원시값으로 형변환이 되어 연산됩니다.
const obj = {};
obj + 1; // '[object Object]1'
{} + 1; // '{}' 가 block으로 취급
놀랍게도 Object도 toString() 함수가 존재하고, 그 결과값은 [object Object]입니다.
array와 동일하게 아래와 같은 과정을 거쳐 연산을 하게 됩니다.
obj + 1 => obj.toString() + 1 => '[object Object]' + 1 => '[object Object]1'
==연산에서의 형변환
다른 타입을 가진 두 값이 같은지 비교하기 위해서는 당연히 형변환이 선행으로 이루어져야 합니다.
각 피연산자가 == 연산에서 각각 어떻게 형변환이 되는지 알아봅시다. (=== 연산자는 형변환이 발생하지 않습니다.)
if(1 == '1') {
console.log('Hello World!'); // 출력 O
}
if(1 == '') {
console.log('Hello World!'); // 출력 X
}
if(0 == '') {
console.log('Hello World!'); // 출력 O
}
Number(''); // 0
0.toString(); // '0'
간단한 예시로 문자열과 숫자를 비교했을 때, 문자열이 숫자로 변환됨을 알 수 있습니다.
만약, 숫자가 문자열로 변환이 되는 것이라면 세 번째 if문이 동작하지 않아야지만 동작하기 때문에 숫자가 문자열로 변환되는 것이 아님을 알 수 있습니다.
참조값이 == 연산에 사용되는 경우에는, 위에서 설명한 것과 마찬가지로 참조값이 우선 toString() 연산을 통해 원시값으로 형변환됩니다. 그리고 마찬가지로 동일한 연산을 수행하게 됩니다.
Truthy와 Falsy
Truthy 와 Falsy는 자바스크립트에서 boolean을 기대하는 구문에서 각 값이 true와 false 중 어떤 값을 가지냐를 나타내는 값입니다.
즉, if, while 등의 구문에서 사용되는 값이 true나 false를 나타내는 것입니다.
먼저, Falsy한 값은 0, -0, 0n(bigint), '', null, undefined, NaN이 있습니다.
Truthy한 값은 Falsy한 값을 제외한 모든 값입니다.
0 // falsy => false
'' // falsy => false
123 // truthu => true
'Hello World' // truthy => true
[] // truthy => true - string으로 변환되지 않음
[1, 2, 3] // truthy => true - string으로 변환되지 않음
여기서 주의해야 할 점은, truthy와 falsy를 결정하는 과정에서는 형변환이 발생하지 않습니다.
즉, array가 String으로 변환되지 않습니다.
if([]) {
console.log('어, 이게 왜 되지?'); // [] = truthy, 출력 O
}
if(0) {
console.log('어, 이게 왜 안되지?'); // 0 = falsy, 출력 X
}
요약
- 문자열과 숫자의 + 연산은 숫자가 문자열로 형변환된다.
- 문자열과 숫자의 + 연산을 제외한 모든 수학 연산에서 문자열이 숫자로 형변환된다.
- 문자열과 숫자의 == 연산은 문자열이 숫자로 형변환된다.
- 참조값은 연산을 위해 원시값으로 변환되어야 하며 그 값은 toString() 결과이다.
- 따라서 [] == 0 의 값은 '' == 0 , 0 == 0 과정에 따라 true를 반환한다.
'javascript' 카테고리의 다른 글
[javascript] Symbol (0) | 2022.01.08 |
---|---|
[javascript] 옵셔널 체이닝 '?.' (0) | 2022.01.07 |
[javascript] nullish 병합 연산자 '??' (0) | 2022.01.06 |
[javascript] padStart(), padEnd() (lpad(), rpad()) (0) | 2022.01.05 |
[Javascript] 비동기(async) 처리와 콜백(callback) 함수 (0) | 2021.12.28 |
댓글