가오리의 코딩일기

9장 타입 변환과 단축 평가 본문

HTML+CSS+JavaScript/DeepDive

9장 타입 변환과 단축 평가

류경혜 2022. 8. 9. 14:00

💡 암묵적 타입 변환(implicit coercion), 타입 강제 변환(type coercion)

→ 자바스크립트 엔진은 표현식을 평가할 때 코드 문맥에 부합하도록 자동 변환 수행

→ 재할당이 아닌 새로운 타입의 값을 만들어 단 한 번 사용하고 버린다

→ 표현식을 에러 없이 평가하기 위해서

 

 

 

🧩 문자열 타입으로 변환

→ +연산자는 피연산자 중 문자열이 존재하면 문자열 연결 연산자로 동작한다

→ 템플릿 리터럴의 표현식 삽입: 표현식의 평가 결과를 문자열 타입으로 암묵적 타입 변환한다

`1 + 1 = ${1+1}` // "1 + 1 = 2"

→ 숫자 타입

0 + "";   // "0"
-0 + "";  // "0"
1 + "";   // "1"
-1 + "";  // "-1"
NaN + ""; // "NaN"
Infinity + "";  // "Infinity"
-Infinity + ""; // "-Infinity"

→ 불리언 타입

true + "";  // "true"
false + ""; // "false" 

→ null 타입

null + ""; // "null"

→ undefined 타입

undefined + ""; // "undefined"

→ 심벌 타입

(Symbol()) + ""; // TypeError: Cannot convert a Symbol value to a string

→ 객체 타입

({} + "");             // "{object Object}"
Math + "";             // "[object Math]"
[] + "";               // ""
[10, 20] + "";         // "10,20"
(function () {} + ""); // "function(){}"
Array + ""; // "function Array() { [native code }"

 

 

 

 

🧩 숫자 타입으로 변환

→ 피연산자를 숫자 타입으로 변환할 수 없을 때 평가 결과: NaN

→ 빈 문자열, 빈 배열, Null, false는 0, true는 1로, 배열, undefined는 NaN로 변환

→ 문자열 타입

+"";  // 0
+"0"; // 0
+"1"; // 1
+"string"; // NaN

→ 불리언 타입

+true; // 1
+false; // 0

→ null 타입

+null; // 0

→ undefined 타입

+undefined; // NaN

→ 심벌 타입

+Symbol(); // TypeError: Cannot convert a Symbol value to a number

→ 객체 타입

+{}; // NaN
+[]; // 0
+[10, 20]; // NaN
+function () {}; // NaN

 

 

 

 

🧩 불리언 타입으로 변환

🔗 truthy: 참으로 평가되는 값

function isFalsy(v) {
  return !v;
}
function isTruthy(v) {
  return !!v;
}
// 모두 true를 반환한다
isFalsy(false);
isFalsy(undefined);
isFalsy(null);
isFalsy(0);
isFalsy(NaN);
isFalsy(" ");

// 모두 true를 반환한다
isTruthy(true);
isTruthy("0");
isTruthy({});
isTruthy([]);

→ truthy 값을 true로 변환하기 때문에 아래의 모든 if블록을 실행하게 된다

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)

🔗 falsy: 거짓으로 평가되는 값

 

 

 

💡 명시적 타입 변환(explicit coercion), 타입 캐스팅(type casting)

→ 개발자가 의도적으로 값의 타입을 변환하는 것

→ 방법1: 표준 빌트인 생성자 함수를 new 연산자 없이 호출

→ 방법2: 빌트인 메서드 사용

🔗 표준 빌트인 생성자 함수 vs. 빌트인 메서드

더보기

→ 모두 자바스크립트에서 기본 제공하는 함수

→ 표준 빌트인 생성자 함수: 객체 생성을 위한 함수, new 연산자와 함께 호출

→ 빌트인 메서드: 자바스크립트에서 기본 제공하는 빌트인 객체의 메서드

     추가적인 설명은 21장에서 이어진다

 

 

 

 

🧩 문자열 타입으로 변환

→ String 생성자 함수를 new 연산자 없이 호출하는 방법

// 숫자 → 문자열
String(1);        // "1"
String(NaN);      // "NaN"
String(Infinity); // "Infinity"

// 불리언 → 문자열
String(true);  // "true"
String(false); // "false"

→ Object.prototype.toString 메서드를 사용하는 방법

// 숫자 → 문자열
(1).toString();        // "1"
(NaN).toString();      // "NaN"
(Infinity).toString(); // "Infinity"

// 불리언 → 문자열
(true).toString();  // "true"
(false).toString(); // "false"

→ 문자열 연결 연산자를 이용하는 방법

// 숫자 → 문자열
1 + "";   // "1"
NaN + ""; // "NaN"
Infinity + "";  // "Infinity"

// 불리언 → 문자열
true + "";  // "true"
false + ""; // "false"

🔗 toString vs. String

더보기

→ 형변환만 할 때는 차이가 없다, 완전히 같은 결과

→ String()은 null, undefined에서 작동하지만 toString()은 아니다

→ toString() : 특정 진수로 객체를 표현한 문자열로 반환

→ String() : 문자로 형 변환하여 반환

let value = null;
String(value);      // "null"
value.toString();  // TypeError: Cannot read properties of null (reading 'toString')

 

 

 

 

🧩 숫자 타입으로 변환

→ Number 생성자 함수를 new 연산자 없이 호출하는 방법

// 문자열 → 숫자
Number('0'); // 0
Number('-1'); // -1
Number('10.53'); // 10.53

// 불리언 → 숫자
Number(true);  // 1
Number(false); // 0

→ parseInt, parseFloat 함수를 사용하는 방법(문자열만 숫자 타입으로 변환 가능)

// 문자열 → 숫자
parseInt('0'); // 0
passeInt('-1'); // -1 
parseInt('10.53'); // 10
parseFloat('10.53'); // 10.53

→ +단항 산술 연산자를 이용하는 방법

// 문자열 → 숫자
+"0"; // 0
+"-1"; // -1
+"10.53"; // 10.53

// 불리언 → 숫자
+true; // 1
+false; // 0

→ *산술 연산자를 이용하는 방법

// 문자열 → 숫자
"0" * 1; // 1 
"-1" * 1; // -1
"10.53" * 1; // 10.53

// 불리언 → 숫자
true * 1; // 1
false * 1; // 0

🔗 parseInt vs. Number

더보기

→ parseInt(value) : 숫자와 문자 중 정수만 인식하여 정수로 리턴한다[문자가 앞에 있는 경우 불가능]

→ Number(value) : 숫자로 이루어진 것만 숫자로 리턴(정수, 실수 모두 가능)

 

 

 

 

🧩 불리언 타입으로 변환

→ Boolean 생성자 함수를 new 연산자 없이 호출하는 방법

// 문자열 → 불리언
Boolean("x");     // true
Boolean("");      // false
Boolean("false"); // true

// 숫자 → 불리언
Boolean(0);        // false
Boolean(1);        // false
Boolean(Infinity); // true

// null → 불리언
Boolean(null); // false

// undefined → 불리언
Boolean(undefined); // false

// 객체 → 불리언
Boolean({}); // true
Boolean([]); // true

→ ! 부정 논리 연산자를 두 번 사용하는 방법

// 문자열 → 불리언
!!'x';     // true
!!'';      // false
!!'false'; // true

// 숫자 → 불리언
!!0;        // false
!!1;        // true
!!NaN;      // false
!!Infinity; // true

// null → 불리언
!!null; // false

// undefined → 불리언
!!undefined; // false

// 객체 → 불리언
!!{}; // true
!![]; // true

 

 

 

 

 

💡 단축 평가(short-circuit evaluation)

🧩 논리 연산자를 사용한 단축 평가

→ 논리합(||) 또는 논리곱(&&)의 평가 결과는 불리언 값이 아닐 수도 있다.

→ 논리합과 논리곱은 언제나 2개의 피연산자 중 어느 한쪽으로 평가된다.

→ 논리 연산의 결과를 결정하는 피연산자를 타입 변환하지 않고 그대로 반환한다

→ 표현식을 평가하는 도중에 평가 결과가 확정된 경우 나머지 평가 과정을 생략한다

 

✏️ 논리합(&&)

→ 두 개의 피연산자가 모두 true로 평가될 때 true를 반환한다

좌항에서 우항으로 평가가 진행된다

'Cat' && 'Dog'; // "Dog"

→ 첫 번째 피연산자 ‘Cat’은 Truthy 값으로 true

→ 첫 번째 피연산자가 true이기 때문에 두 번째 피연산자까지 평가해 보아야 위 표현식을 평가할 수 있다

→ 논리 연산의 결과를 결정하는 두 번째 피연산자, 문자열 ‘Dog’를 그대로 반환한다

→ 어떤 조건이 Falsy 값일 때 논리합 연산자 표현식으로 if문을 대체할 수 있다

let done = true;
let message = '';

if(done) message = '완료';
message = done && '완료';
console.log(message); // 완료

 

 

 

 

✏️ 논리곱(||)

→ 두 개의 피연산자 중 하나만 true로 평가되어도 true를 반환한다

→ 마찬가지로 좌항에서 우항으로 평가가 진행된다

'Cat' || 'Dog'; // "Cat"

→ 첫 번째 피연산자 ‘Cat’은 Truthy 값으로 true

→ 첫 번째 피연산자가 true이기 때문에 두 번째 피연산자는 평가할 필요가 없다

→ 논리 연산의 결과를 결정하는 첫 번째 피연산자(’Cat’)를 그대로 반환한다

→ 어떤 조건이 Truthy 값일 때 논리곱 연산자 표현식으로 if문을 대체할 수 있다

let done = false;
let message = '';

if(!done) message = '미완료';
message = done || '미완료';
console.log(message); // 미완료

 

 

 

 

✏️ 객체를 가리키기를 기대하는 변수가 null 또는 undefined가 아닌지 확인하고 프로퍼티를 참조할 때

→ 객체: 키와 값으로 구성된 프로퍼티의 집합

→ 변수의 값이 객체가 아니라 null 또는 undefined인 경우 타입에러가 발생한다

let elem = null;
let value = elem.value; // TypeError: Cannot read property 'value' of null
let elem = null;
let value = elem && elem.value; // null

 

 

 

 

✏️ 함수 매개변수에 기본값을 설정할 때

→ 함수 호출 시 인수를 전달하지 않으면 매개변수에 undefined가 할당된다

→ 단축평가를 통해 매개변수의 기본값을 설정하면 undefined로 인해 발생할 에러를 방지한다

// 매개변수의 기본값 설정
function getStringLength(str = ''){
	return str.length;
}
getStringLength(); // 0
getStringLength('hi'); // 2
// 단축평가를 사용한 매개변수의 기본값 설정
function getStringLength(str){
	str = str || "";
	return str.length;
}
getStringLength(); // 0
getStringLength('hi'); // 2

 

 

 

 

 

 

🧩 옵셔널 체이닝(optional chaining) 연산자: ?.

→ 좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고 그렇지 않으면 우항의 프로퍼티 참조를 이어간다

// elem이 null 또는 undefined이면 undefined를 반환, 그렇지 않으면 우항의 프로퍼티 참조를 이어간다
let elem = null;
let value = elem?.value;
console.log(value); // undefined
// elem이 Falsy 값이면 elem으로 평가되고 elem이 Truthy 값이면 elem.value로 평가된다
let elem = null;
let value = elem && elem.value;
console.log(value); // undefined

→ 논리 연산자 &&는 좌항 피연산자가 Falsy 값(false, undefined, null, 0, -0, NaN, ‘’)이면 좌항의 피연산자를 그대로 반환한다

→ 좌항 피연산자가 Falsy값인 0이나 ‘’인 경우도 마찬가지지만 0이나 ‘’은 객체로 평가될 수 있다

let str = '';
// 문자열의 길이를 참조한다
let length = str && str.length;
// 문자열의 길이를 참조하지 못한다
console.log(length); // ''

→ 옵셔널 체이닝 연산자는 좌항 피연산자가 falsy 값이라도 null이나 undefined가 아니면 우항의 프로퍼티 참조를 이어간다

let str = '';
let length = str?.length;
console.log(length); // 0

 

 

 

 

 

 

🧩 null 병합 연산자(nullish coalescing): ??

→ 좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환하고 그렇지 않으면 좌항의 피연산자를 반환한다

→ 변수에 기본값을 설정할 때 유용하다

let foo = null ?? 'default string';
console.log(foo); // "default string"
// Falsy 값인 0이나 ''도 기본값으로서 유효하다면 예기치 않은 동작이 발생할 수 있다
let foo = '' || 'default string';
console.log(foo); // "default string"
// 좌항의 피연산자가 Falsy 값이라도 null 또는 undefined가 아니면 좌항의 피연산자를 반환한다
let foo = '' ?? 'default string';
console.log(foo); // ""