본문 바로가기
JavaScript Study

JavaScript - #10. 타입변환 & 단축평가

by KMS_99 2023. 8. 25.

이전에 자바스크립트의 타입을 알아본적이 있다.

자바스크립트는 개발자에 의도에 따라 다른 타입으로 변환이되는 명시적 타입 변환과

개발자의 의도와는 상관없이 자바스크립트 엔진에 의해 암묵적으로 타입이 변환되는 암묵적 타입변환이 이루어진다.

 

우리가 이 두가지 경우를 알고 있어야 프로젝트 도중 이로인한 오류를 예방하고, 더욱 효과적인 코딩을 할 수가 있다.

지금부터 이 두가지  경우에 대해서 알아보겠다.

 

먼저 간단한 코드를 통해 이 두가지 변환 방식의 느낌을 알아보자.

 

//명시적 타입 변환 ( explicit coercion )
let x = 10;
let str = x.toString(); // toString()은 원 변수를 변화시키지 않는다.
console.log (typeof x, x);
console.log (typeof str, str);

//암묵적 타입 변환 ( implicit coercion )
x = 10;
str = x+''; //여기서 연산자인 + 는 문자열 연결 연산자로 작동하여 str에는 string type으로 저장됨.
console.log(typeof str, str);

출력 값 : 

number 10
string 10
string 10

x.toString() 메서드를 통해서 의도적인 number type의 변수인 x 를 새로운 변수 str에 string type으로 할당 한 것을 볼 수 있다. 이처럼 사용자가 의도적으로 형 변환을 시키는 것을 명시적 타입변환, 타입 캐스팅이라고 한다.

그렇다면 .toString() 메서드를 실행 한 후 기존 x 변수의 type도 변할까?

아니다 기존의 값은 기존 type으로 유지되며, .toString() 일시적으로 type 변화가 일어난다. 따라서 새로운 변수 str에 저장해서 그 값을 유지할 수 있는 것이다. 

 

다음 암묵적 타입 변환에서는 어떤방식으로 타입을 변경하였을까?

x라는 숫자타입의 변수에 +' '을 하여 새로운 변수 str에 값을 저장한것을 볼 수 있다.

이전에 연산자에 대하여 배운적이 있다. + 는 산술 연산자의 역할을 하기도 하지만, 이렇게 피 연산자  중 한가지 이상이 string 타입이라면 문자열 연결 연산자로 용도가 바뀐다.

따라서 x + ' '은 문자열 10이라는 값으로 타입 변화하게 되고 이 값이 새로운 변수 str에 할당된다.

암묵적 타입 변환도 명시적 타입 변환과 마찬가지로 일시적인 형변환일 뿐 기존 원시값에는 영향을 미칠 수 없기 때문에 새로운 변수에 저장하여 유지하는 것이다.

 

대충 각각의 개념의 느낌을 이해했다고 생각한다. 이제 하나하나씩 자세히 내용을 배워보도록 하자.


1. 암묵적 타입 변환

자바스크립트 엔진은 표현식을 평가할 때 개발자의 의도와는 상관없이 코드의 문맥을 고려하여 암묵적으로 데이터 타입을 강제 변환 할 때가 있다.

 

- 문자열 타입으로 암묵적 타입 변환

//1 문자열
console.log (1 + '2') //string type '12', + 연산자가 문자열 연결 연산자로 작용 (피연산자 중 1개 이상이 문자열일 경우)
console.log (`1 + 1 = ${1 + 1}`) //string type '1 + 1 = 2' / ES6에서 도입된 템플릿 리터럴의 표현식 삽입

//number type to string type
console.log (0+'') // string type '0'
console.log (-0+'') // string type '0'
console.log (1+'') // string type '1'
console.log (-1+'') //string type '-1'
console.log (NaN+'') //string type 'NaN'
console.log (Infinity+'') // string type 'Infinity'
console.log (-Infinity+'') // string type '-Infinity'

//boolean type to string type
console.log (true +'') //string type 'true'
console.log (false + '') // string type 'false'

//null type to string
console.log( null+'' ) // string type 'null'

//undefined type to string
console.log( undefined+'') // string type 'undefined'

//Symbol type to string
console.log(Symbol() + '') // =>TypeError : Cannot convert a Symbol value to a string

//Object type to string
console.log({}+'') // string type '[Object, object]'
console.log(Math +'') // string type '[Object, math]'
console.log([]+'') // ''
console.log([10, 20]+'') //string type '10,20'
console.log(function(){}+'') // string type 'function(){}'
console.log(Array+'') // string type 'function Array(){[native code]}'

대부분 (+' ')을 통한 형변환이 되고 예측이 가능하지만, Object type과 Sympol type에서 문자열로의 암묵적 타입 변환 부분에서 혼란이 오는 것 같다. 

 

- 숫자 타입으로 암묵적 타입 변환

console.log(1-'1') // number type 0
console.log(1*'10') // number type 10
console.log(1/'one') //number type NaN, 'one'은 숫자로 변환이 불가능

console.log('1'>0) //boolean type true, 결과는 boolean 값이지만, 비교 연산 과정에서 string type에서 number type으로 타입변환

//string type to number type
console.log(+'') // number type 0
console.log(+'0') // number type 0
console.log(+'1') // number type 1
console.log(+'string') // number type NaN

//boolean type to number type
console.log(+true) //number type 1
console.log(+false) // number type 0

//null type to number type
console.log(+null) // number type 0

//undefined type to number type
console.log(+undefined) // number type NaN

//Symbol type to number type
console.log(+Symbol()) //TypeError : Cannot convert a Symbol value to a number

//Object type to number type
console.log(+{}) // number type NaN
console.log(+[]) // number type 0
console.log(+[10, 20]) // number type NaN
console.log(+function(){}) // number type NaN

여기서 주의해야할 점은 Symbol Type은 암묵적 타입변환이 되지 않는 것과 빈배열을 제외한 모든 Object type과 undefined type은 변환이 불가능하여 NaN이 된다는 것이다.

 

-Boolean 타입으로 암묵적 타입 변환

// Falsy Value
// false, undefined, null, 0/-0, NaN, ''
// Falsy Value는 거짓(false)으로 판단
// 나머지는 Truthy value로 참(true)으로 판단 
console.log(!!false);
console.log(!!undefined);
console.log(!!null);
console.log(!!0);
console.log(!!(-0));
console.log(!!NaN);
console.log(!!'');

Boolean 타입으로의 암묵적 타입 변환은 Falsy Value 만 확인 하면 된다. 

Falsy Value : false, undefined, null, 0/-0, NaN, ' ' 

Falsy Value를 제외한 것들은 Truthy Value로 참(true)로 판단하면 되겠다.


2. 명시적 타입 변환

개발자의 의도에 따라서 명시적으로 타입을 변경하는 것이다.

사실 암묵적 타입 변환의 경우도 의도에 따라서는 명시적 타입 변환이 될 수 있다.

위에서 언급했던 방법 외에 명시적 타입변환을 할 수 있는 방법에 대해 알아보자.

 

- 문자열 타입으로 암묵적 타입 변환

console.log(String(1)) // string type "1"
console.log(String(NaN)) // string type "NaN"
console.log(String(Infinity)) // string type "Infinity"

console.log(String (true)) // string type "true"
console.log(String(false)) // string type "false"

console.log((1).toString()) // string  type "1"
console.log((NaN).toString()) // string type "NaN"
console.log((Infinity).toString()) // string type "Infinity"

console.log((true).toString()) // string type "true"
console.log((false).toString()) // string type "false"

자바스크립트 표준 빌트인 생성자 함수를 new 없이 생성하는 방식 (String())과 ().toString 매서드를 사용하면 다른 타입의 값을 string으로 변환할 수 있다.

 

- 숫자 타입으로 암묵적 타입 변환

console.log(Number('0')) // number type 0 
console.log(Number('-1')) // number type -1
console.log(Number('10.53')) // number type 10.53

console.log(true) // number type 1
console.log(false) // number type 0

//parseInt/Float 방식은 문자열 > 숫자 타입만 변환가능
console.log(parseInt('0')) // number type 0 
console.log(parseInt('-1')) // number type -1
console.log(parseFloat('10.53')) // number type 10.53

문자열과 마찬가지로 표준 빌트인 생성자 함수를 사용할 수 도 있으며, 내장 함수인 parseInt/Float를 사용하면 명시적 타입 변환을 할 수 있다. 이때 parseInt/Float는 문자열에서 숫자 타입만 변환이 가능하니 주의해야한다.

 

- Boolean 타입으로 암묵적 타입 변환

console.log(Boolean('x')) // boolean type true
console.log(Boolean('')) // boolean type false
console.log(Boolean('false')) // boolean type true
console.log(Boolean(0)) // boolean type false 
console.log(Boolean(1)) // boolean type true
console.log(Boolean(NaN)) // boolean type false 
console.log(Boolean(Infinity)) // boolean type true
console.log(Boolean(null)) // boolean type false
console.log(Boolean(undefined)) // boolean type false
console.log(Boolean({})) // boolean type true
console.log(Boolean([])) // boolean type true

Boolean 타입도 표준 빌트인 생성자 함수로 변환이 가능하다.


3. 단축평가

앞서 배운 암묵적 타입 변환을 이용하여 우리는 단축평가라는 것을 할 수 있다.

중요한 개념을 순서대로 알아보겠다.

 

- 논리연산자를 이용한 단축평가

논리 합( || )과 논리 곱(&&)에 대하여 이전시간에 알아보았다.

이 둘의 반환 값이 암묵적타입변환을 사용하면 Boolean 값이 아닌 다른 값을 반환 할 수 있다.

이 예제를 살펴보자

console.log('Cat'&&'Dog'); // return> Dog

예제에서는 'Cat'과 'Dog'의 논리 곱을 계산하고 있다.

우리가 지금까지 배운 개념으로 예제를 분석해보자

'Cat'은 Truthy 값이다. 즉 'Cat'을 Boolean 값으로 암묵적 타입 변환이 된다면 true의 값을 가진다.

그렇다면 예제의 논리 곱에서 true, false를 결정하는 피연산자는 'Dog'가 될 것이다.

논리곱 연산자 표현식에서는 true, false를 결정하는 피 연산자를 값으로 가지게 된다.

 

그렇다면 다음 예제의 값은 무엇일까?

console.log(""&&"Dog")

위 논리와 똑같이 적용해보겠다.

연산자 기준 좌항에 있는 피연산자는 "" 으로 빈 문자열이다.

빈 문자열은 Falsy 값중 하나로 Boolean으로 타입 변환 될 시 false의 값으로 타입이 변환된다.

논리 곱은 두개의 피연산자 모두 true이여야 true를 반환하지 않는가

이미 좌항에서 평가 결과가 결정되었다.

따라서 예제의 출력값은 빈 문자열 그대로 출력이 된다.

 

다음으로는 논리 합 예제를 살펴보자

console.log ("Cat"||"Dog"); // return > Cat

논리 합도 역시 똑같이 작동한다.

논리 합은 두개의 피 연산자 중 하나만 true이면 true를 반환한다.

따라서 좌항에 있는 "Cat"이 Boolean으로 변환 시 true의 값을 가지게 되어 평가 결과는 정해진다.

출력 값이 그래서 좌항에 있는 "Cat"이 된다.

console.log (""||"Dog");

그렇다면 이경우에는 어떤 값이 반환될까?

좌항이 false의 값을 가지고 우항에서 true의 값을 가지니 "Dog"가 반환 될 것이다.  

 

단축평가는 객체를 가리키는 변수를 체크하는데 많이 사용되고있다. 해당 내용은 추후에 배울 예정이다.

 

논리 연산자를 사용한 단축평가는 동작원리만 알고 있다면 논리 곱이든 논리 합이든 똑같이 적용될 수 있기 때문에 해당 개념을 잘 이해하자.

 

 + 추가 개념

 

- 옵셔널 체이닝 연산자

ES11 (ECMAScript 2020)에서 도입된 옵셔널 체이닝은 ( ?. ) 연산자를 사용하며 좌항에는 피연산자가 null 또는 undefined인 경우 undefined를 반환하고, 그렇지 않다면 우항의 프로퍼티를 참조한다.

 

왜 falsy 값 전체가 아닌 null, undefined만 필터링하는 걸까?

 

객체에서 프로퍼티를 참조하는데 객체 변수가 null과 undefined의 값을 가지고 있다면 오류가 발생하게 된다.

TypeError : Cannot read property of undefined 

 

따라서 ES11에서는 객체를 사용함에 있어 객체 변수가 null과 undefined이기에 발생하는 오류를 방지하기 위해 옵셔널 체이닝 연산자를 도입했다고 할 수 있다.   

 

let obj;
console.log (obj?.property); // return > undefined
console.log (obj.property); // TypeError

결과 :

 

'JavaScript Study' 카테고리의 다른 글

JavaScript - #12. 원시값과 객체 (1)  (0) 2023.08.28
JavaScript - #11. 객체 리터럴  (0) 2023.08.27
JavaScript - #9. 제어문 (2)  (0) 2023.08.25
JavaScript - #8. 제어문 (1)  (0) 2023.08.25
JavaScript - #7. 연산자 (2)  (0) 2023.08.24