기초부터 완성까지, 프런트엔드를 읽고 정리한 내용입니다.
자바스크립트에는 명시적 강제 변환과 암시적 강제 변환 두 가지의 타입 변환이 존재하는데 명시적 강제 변환은 의도적인 타입 변환을 나타내는 것이고, 암시적 강제 변환은 표현식의 평가 중 타입이 변환되는 것이다.
의도를 가지고 타입을 변환 하는 것
문자열로 변환
String()
호출
ECMAScript의ToString
추상 연산을 기준으로 이뤄진다. 객체의 경우 원시 타입으로 변환한 뒤 다시 한번 ToString 추상 연산을 수행한 값을 반환한다.
Symbol
은 문자열 숫자로 변환될 경우 TypeError가 발생하는데 객체의 다른 프로퍼티에 접근하는 것을 방지 하지 위해서이다.
toString()
메서드 이용
둘의 차이점은 null
과 undefined
타입에서 나타난다.
console.log(String(null)) // 'null'
console.log(String(undefined)) // 'undefined'
undefined.toString(); // TypeError 발생
null.toString(); // TypeError 발생
null
과 undefined
타입은 값이 비어 있음, 할당되지 않은 상태를 나타내는 원시 타입이므로 toString() 메서드를 호출할 수 없다. 객체가 아니기 때문에 객체에서 사용할 수 있는 프로퍼티들을 사용할 수 없다. 반면에 String()함수는 정의된 규칙에 따르기 때문에 문자열로 명시적 강제 변환이 가능하다.
숫자로 변환
Number()
ECMAScript의 ToNumber
추상 연산 명세를 기준으로 반환된다.
BigInt, Symbol은 typeError 가 발생한다. BigInt는 큰 정수의 연산을 위해 나온 타입이기 때문에 숫자와 타입이 구분되어야 하기 때문이다.
parseInt()
함수
문자열만 대상으로 변환한다. 문자열이 아닌 경우에는 해당 값을 문자열로 변환한 후에 사용한다. 두 번째 인자는 기수를 의미한다. (10일 경우 10진수로 변환) 생략할 경우 첫번째 인자를 기준으로 추정하여 변환하므로 의도 하지 않은 결과가 나올 수도 있다.
console.log(parseInt('10',10)) // 10
Number()
는 숫자로 변경 불가능한 문자가 있으면 싸가지 없이 바로 NaN을 반환 하지만, parseInt
는 최대한 숫자로 변환하여 결과를 반환한다.
console.log(Number('10A', 10)); // NaN
console.log(parseInt('10A', 10)); //10
불리언으로 변환
ECMAScript의 ToBoolean
추상 연산 명세를 기준으로 반환된다.
falsy
값의 기준 또한 위의 명세를 따른 것이다.
Boolean()
함수를 호출하는 방법과 부정 연산자를 사용하는 방법이 있으며 둘 다 동일한 결과를 반환한다.
객체의 원시 타입 변환은 문자열로 변환, 숫자로 변환 두 가지로 나눌 수 있으며 valueOf()
, toString()
이 쓰인다. ECMAScript에서는 ToPrimitive 추상 연산으로 정의 하고 있다.
문자열로 변환
toString()
을 호출한다. 없으면 prototype.toString()
메서드를 실행한다. Object.prototype.toString()
는 결과값으로 '[Object object]'
문자열을 반환한다.valueOf()
메서드를 호출한다. 없다면 Object.prototype.valueOf()
을 실행한다.valueOf()
메서드의 결과 값이 원시 타입이라면 그 결과를 문자열로 변환하여 반환하고, 그렇지 않다면 TypeError
가 발생한다.console.log(String({})) // '[Object object]'
숫자로 변환
valueOf()
메서드를 호출한다. 없다면 Object.prototype.valueOf()
을 실행한다. Object.prototype.valueOf()
메서드는 결과값으로 객체를 그대로 반환한다.toString()
을 호출한다. 없으면 기본적으로 prototype.toString()
메서드를 실행한다. toString()
의 결과가 원시 타입이라면 그 결과를 숫자로 변환하여 반환하고 그렇지 않다면 TypeError가 발생한다.console.log(Number({})); // NaN
배열, Date 정규식과 같은 특수한 객체들은 자체적인 toString()
또는 valueOf()
메서드를 가지고 있다.
암시적 강제 변환은 연산 중에 내부적으로 타입을 변환하는 것이다. 이 또한 ECMAScript 명세의 기준대로 정확하게 동작하고 있다.
덧셈 연산자
피연산자 중 하나가 문자열 타입인 경우 나머지 타입도 문자열로 변환하여 병합한다.
console.log(1 + ''); // '1'
피연산자 중 하나가 객체이며 문자열로 변환 가능한 경우 문자열로 변환하여 연산한다.
console.log(1 + {}); // '1[object Object]'
피연산자가 모두 문자열, 객체가 아니면 숫자로 변환하여 연산한다. 만약 변환 결과 타입이 다르면 TypeError가 발생한다.
console.log(1 + true); //2
동등 연산자
동등 연산자의 가장 큰 특징은 암시적 강제 변환을 허용하는 것이다. 피연산자 타입이 서로 같은 경우에는 변환하지 않는다.
피연산자 중 하나는 문자열, 하나는 숫자인 경우 문자열을 숫자로 변환하여 동등함을 비교한다.
console.log(1 == '1'); // true
문자열, BigInt => 문자열을 Bigint로 변환하여 비교
null == undefined 인경우 동등
피연산자 중 하나가 불리언이면 불리언을 숫자로 변환하여 동등함 비교
console.log(ture == 1) ; // true
객체 == (문자열, 숫자, BigInt, symbol) 일 경우 객체를 원시타입으로 비교하여 동등함을 비교
console.log('[object Object]' == {}); // true
숫자 == BigInt 인 경우 내부적인 숫자 비교 알고리즘에 따라 비교한 결과를 반환
가독성이 떨어지는 경우가 생길 수 있다.
console.log(true == '1'); //true
비교 연산자
문자열 비교
각 문자를 알파벳 순서로 비교한다.
console.log('1' < '04') // false
왼쪽부터 '1'과 '0'을 비교하고 그 다음 문자를 비교한다.
객체인 경우 원시타입으로 변환한 후에 비교한다.
console.log(['a'] < ['b']) // true
문자열 외
다른 타입 간의 비교 연산에서 암시적인 강제 변환을 막을 수 없다.
조건 표현식
모든 값은 불리언으로 변환되어 조건 표현식에서 평가된다.
const a = 0;
const b = 'javscript';
const c = null
if (a) {
console.log('falsy');
}
while (b) {
console.log('truthy');
break;
}
console.log(c ? 'truthy' : 'falsy'); // 'falsy'
논리 연산자
자바스크립트 논리 연산자의 특이한 점은 논리 연산자의 값이 불리언 타입이 아닐 수 있다는 것이다.
const a = null;
const b = 'javascript';
const c = 1;
console.log(a && b) ; //null
console.log(b || c) ; //'javascript'
디폴트 값을 설정하거나 조건에 따라 함수를 실행할 때 유용하다. 리액트에서 컴포넌트를 조건에 따라 렌더링할 때 자주 사용한다. 만약 falsy 값이 아닌 null, undefined처럼 값이 비어 있는 경우에만 디폴트 값을 설정하고 싶을 때는 ES2020에서 등장한 null 병합을 사용할 수 있다.
const a = ''
const b = a ?? 'default';