javascript/DeepDive

[DEEP DIVE] 9. 타입 변환과 단축 평가

hw.kr 2022. 10. 3. 16:26

Js에서 표현식의 평과 결과로 만들어지는 모든 값은 타입을 가진다.

앞에서는 어떤 타입이 있는지, 타입이 왜 필요한지에 대해서 알아봤다.

이번에는 타입의 변환에 대해서 알아보자~

 

1. 타입 변환?

📌 명시적 타입 변환

var age = 24;
var str = age.toString();
console.log(typeof str, str); // String 24
console.log(typeof x , x); // number 24

위의 코드와 같이 코드 작성자가 의도적으로 변수의 타입을 변환하는 것을 명시적 타입 변환 이라고 한다.

 

📌 암묵적 타입 변환

var x = 10;
console.log(typeof x, x) // number 10

var str = x + '' // 10 + ''
console.log(typeof x, x) //string 10

x += x + ''
console.log(typeof x, x) //???

위의 코드와 같이 코드 작성자가 명시적으로 toString(), Number()을 사용하지 않고도 연산자를 통해서,

처음 선언할때의 변수의 타입과 달라지는 것을 암묵적 타입 변환 이라고 한다.

기억할 것은, 명시적 타입 변환과 암묵적 타입 변환이 기존 변수의 원시 값을 변경하는 것이 아니라

기존 원시 값을 통해서 다른 타입의 새로운 원시 값을 생성하는 것!

Js 엔진은 x + '' 을 평가하기 위해서 기존 x 변수의 원시 값 10을 바탕으로 새로운 문자열 값 '10'을 생성하고 '10' +'' 을 평가 한다.
여기서, 암묵적으로 '10'이 생성되는 것.
문자열 '10'은 x에 재할당 되지 않기 때문에 x의 타입과 값은 그대로!

 

에러없이 평가하기 위해서 새로운 타입의 값('10')을 만들어 평가를 위해서 사용하고 평가가 끝나면 버린다.

종류 명시적 암묵적
특징 의도가 명확히 드러남
어떤 값 어떤 타입으로 변경될지 확실히 알 수 있지만 가독성 측면에서 좋지 않을수도 있음
어떤 값 어떤 타입으로 변경될 수 있을지에 대해서 충분한 지식이 있어 예측할 수 있다면 가독성 측면에서 훨씬 좋은 코드를 짤 수 있다.

이제 각 타입 변환에 대해서 자세하게 알아봅시다~

2. 암묵적 타입 변환

왜 암묵적 타입 변환을 하는거지? => 런타임 전에 가급적 에러 없이 코드 평가를 하기 위해서

1️⃣ 문자열 타입 변환

피연산자중 하나 이상이 문자열이면 문자열 연결 연산자로 작동
문자열 연결 연산자 '+'의 피연산자는 무조건 문자열 이여야 한다.
console.log(1 + '2') // '12'

❕표현식의 피연산자만 암묵적 타입 변환의 대상이 되는것은 아님

console.log(`1 + 1 = ${1 + 1}`);

표현식의 평가 결과를 문자열 타입으로 암묵적으로 변환 하는 템플릿 리터럴도 있다

 

2️⃣ 숫자 타입으로 변환

'+'는 문자열 연결 연산자가 될수도, 단순히 숫자를 더해주는 연산자가 될 수도 있어서 주의해야 하지만,
나머지 산술 연산자 / * % - 들은 예측하기가 쉽다
'+' 를 제외한 산술 연잔자들의 역할은 숫자 값을 만드는 것.
'+' 는 숫자 값을 만들수도, 문자열 연결을 할 수도 있음
10 - '5' // 5
'10' * 8 // 80
'20' / 5 // 4

산술 연산자를 사용한 표현식이 주는 값은 숫자여야 하므로, 숫자 타입이 아닌 피연산자를 숫자 타입으로 변환한다

숫자타입으로 변환할 수 없는 피연산자가 있는 경우 NaN

비교  연산자의 역할은 값 비교를 통해서 불리언 값을 주는 것
피연산자의 크기 비교를 통해서 넘겨줄 값을 판단 하므로 크기 비교는 문맥상 피연산자들이 모두 숫자 타입이여야 한다.
if('1' > 0){
    console.log('hi')
}else{
    console.log('bye')
} // hi

+ 단항 연산자는 숫자 타입으로 변경될 수 있는 피연산자가 숫자 타입이 아니면 숫자 타입으로 암묵적 타입 변환 한다..

말이 어렵네...😂

0으로 변환되는 것만 적어두자.

console.log(+0) // 0
console.log(+"") // 0
console.log(+null) // 0 
console.log(+false) // 0
console.log(+[]) // 0

 

3️⃣ 불리언 타입 변환

if for 삼항 조건 연산자에서 사용되는 조건식으로 만들어지는 결과 값의 타입은 불리언이다
조건식의 평가 결과를 불리언 타입으로 암묵적 타입 변환 한다

불리언 값으로 평가 되어야 할 문맥에서 True or False 로 암묵적 타입 변환된다.

0 or -0, false, undefined, null, NaN, '' 모두 false

나머지 모두 true

1. if('') console.log('hi');
2. if('0') console.log('hi');
3. if(0) console.log('hi');
4. if(null) console.log('hi'); // 2번만 출력

3. 명시적 타입 변환

1️⃣ 문자열 타입 변환

1. String 생성자 함수 new 연산자 없이 사용하기

String(1) // "1"
String(false) // "false"
String(undefined) // "undefined"

2. Object.prototype.toString 메서드 호출

(1).toString(); // '1'
(NaN).toString(); // 'NaN'
(true).toString(); // 'true'

3. 가독성 측면에서 좋은 문자열 연산자 사용

1 + '' // '1'
NaN + '' // 'NaN'
true + '' // 'true

2️⃣ 숫자 타입 변환

1. Number 생성자 함수 new 연산자 없이 사용하기

Number('0') // 0
Number('10.12') // 10.12
Number('true') // 1

2. parseInt, parseFloat 메서드 사용하기

parseInt('0') // 0
parseFloat('10.12') // 10.12
parseInt('true') // 1

3. + 단항 산술 연산자

+false // 0
+'0' // 0
+'10.12' // 10.12

4 * 산술 연산자

'0' * 1 // 0
'-1' * '-1' // 1
true * 1 // 1

3️⃣ 불리언 타입 변환

1. Boolean 생성자 함수 new 연산자 없이 호출

Boolean(null) // false
Boolean(0) // false
Boolean('') // false
Boolean(NaN) // false
Boolean(undefined) // false

2. ! 부정 논리 연산자 두번 사용

!!'x' // true
!!'' // false
!!0 // false
!!NaN // false
!!null // false
!!{} // true
!![] // true

Check

console.log(+[]) // 0
console.log(Boolean([])) // true

빈 배열을 + 단항 연산자를 통해서 숫자 타입으로 암묵적 타입 변환을 거치면 0이 나와서

이때까지 빈 배열은 불리언 값으로 변경 될 때 false 인줄 알았지만 실제로 해보면 true 가 나온다.

위에서 정리 했던 false, undefined, null, 0 or -0, NaN, ' ' 제외 하면 모두 true 다! 헷갈리지 말자~

4. 단축 평가

1. 논리 연산자

논리 연산자 양 옆에 있는 피연산자들은 모두 불리언 값으로 평가될 수 있어야 한다.
논리합|| 또는 논리곱&& 연산자 표현식은 2개의 피연산자 중 어느 한쪽 으로 평가된다.

📌 논리곱

console.log('good' && 'bad'); // 'bad';

논리곱은 두 피연산자 모두 true로 평가 될 때 true로 평가된다.

첫 번째 피연산자 'good'는 true로 평가된다. 아직 논리곱 연산자를 사용한 표현식이 true로 평가된다고 판단할 수 없다.

두 번째 피연산자 'bad'가 남아있다.

여기서, 'bad'가 논리곱 표현식의 평가 결과를 결정한다.  따라서 bad 반환

if('' && 'dog'){
    console.log('hi')
}else{
    console.log('bye')
} // bye

console.log('' && 'bad'); // ''

'' 은 빈 문자열 이기 때문에 불리언 값 false로 평가된다. 논리곱 표현식의 평가 결과를 '' 이 결정하기 때문에 '' 을 출력

한마디로 단축 평가는 논리 연산자의 평가 결과를 결정하는 피연산자를 반환한다고 생각하면 쉽다

 

📌 논리합

console.log('cat' || 'dog') // cat

논리합은 둘 중 하나의 피연산자 모두 true로 평가 되면 true로 평가된다.

첫 번째 연산자 'cat'은 불리언 값이 true이고 논리합이라서 이미 논리합 표현식의 평가결과는 true로 결정 되었다.

따라서 cat을 반환

단축 평가 왜 하지? => 논리합이나 논리곱을 통한 표현식 평가를 하는 도중에 평가 결과가 확정된 경우 나머지 평가 과정을 생략할 수 있다.

 

📌 단축평가로 if문 대체하기

1. &&

// 1. if 문 사용
var finish = true;
var message = '';
if(finish) message = '끝!';

// 2. 단축 평가 사용
message = finish && '끝!';
console.log(message); // 끝!

// 3. message 변수 안만들고 출력해보기
consol.log(finish && '끝!');

2. ||

// 1. if 문 사용
var finish = false;
var message = '';
if(!finish) message = '하는 중!';
console.log(message) // '하는 중!'

// 2. 단축평가 사용
message = finish || '하는 중!';
console.log(message) // '하는 중!'

// 3. message 변수 안만들고 출력해보기
console.log(finishi || message); // '하는 중!'

3. 삼항 연산자

var finish = false
console.log(finish ? '끝!' : '하는 중!'); // '하는 중!'

 

📌 실제로 사용해보기

1. 게시글에 사진 있는 경우에만 렌더링 해주기

프로젝트 했었을때, 게시글에 사진이 있는 경우에만 렌더링 해주는 코드다

이때가 1학기 였는데 그때는, 이게 단축평가 인줄도 모르고 그냥  ''아 사진 있으면 보여주는 코드구나~'' 하면서 만들었다

완전히 탑다운 방식으로 구글링이나 유튜브 찾아 보면서 했었기 때문에..근데 이게 단축평가 였다!

2. 객체에 활용하기

객체의 프로퍼티를 사용해서 값을 참조하려고 하는 경우에, 객체가 null or undefined 인 경우 타입 에러가 발생하지만 단축 평가를 사용하면 에러가 발생하지 않음.

var user = null;
var userName = user && user.name; // null

3. 함수 매개변수에 활용하기

const getLength = (str) => str.length
var len = getLength() // Uncaught TypeError: Cannot read properties of undefined (reading 'length')
console.log(len)

const getLength = (str) => {
    str = str || ''
    return str.length
}

var len = getLength()
console.log(len) // 0

Js 에서 함수를 호출하고, 함수에 아무런 인수를 전달하지 않으면 undefined가 할당되서 타입에러가 발생하는데

단축 평가를 사용해서 아무 인수를 전달하지 않을 경우 str 을 빈 문자열 '' 로 대체 가능

 

❕또 다른 방법

str의 디폴트를 빈 문자열 '' 로 미리 설정

const getLength = (str = '') => {
    return str.length
}

var len = getLength()
console.log(len) // 0

5. 문제

// 무엇이 출력 될까요?
if(+'123'){
    console.log('hi')
}else{
    console.log('bye')
}

if(+'hi'){
    console.log('hi')
}else{
    console.log('bye')
}

var str = 'hello'

if(str){
    console.log('hi')
}else{
    console.log('bye')
}

'javascript > DeepDive' 카테고리의 다른 글

[DEEP DIVE] 11. 원시 vs 객체  (0) 2022.11.02
[DEEP DIVE] 10. 객체 리터럴  (0) 2022.10.28
[DEEP DIVE] 8.제어문  (0) 2022.09.30
[DEEP DIVE] 7. 연산자  (0) 2022.09.28
[DEEP DIVE] 6. 데이터 타입  (0) 2022.09.26