이전에 자바스크립트의 타입을 알아본적이 있다.
자바스크립트는 개발자에 의도에 따라 다른 타입으로 변환이되는 명시적 타입 변환과
개발자의 의도와는 상관없이 자바스크립트 엔진에 의해 암묵적으로 타입이 변환되는 암묵적 타입변환이 이루어진다.
우리가 이 두가지 경우를 알고 있어야 프로젝트 도중 이로인한 오류를 예방하고, 더욱 효과적인 코딩을 할 수가 있다.
지금부터 이 두가지 경우에 대해서 알아보겠다.
먼저 간단한 코드를 통해 이 두가지 변환 방식의 느낌을 알아보자.
//명시적 타입 변환 ( 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);
출력 값 :
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 |