얼마 전부터 10cm의 그라데이션이라는 노래에 빠졌는데 가사 중 이런 문장이 있다.
달콤한 색감이 물들어 조금씩
정신을 차렸을 땐 알아볼 수도 없지
마침 스터디의 이번주 주제가 강제변환이었는데 딱 어울리는 가사가 아닐까 싶다.
달콤?은 모르겠지만 알아볼 수 없게 사람을 헷갈리게 만드는 강제변환에 대해 공부한 내용을 적어보고자 한다.
강제변환은 명시적 강제변환(Implicit Coercion)과 암시적 강제변환(Explicit Coercion)으로 구별할 수 있다.
명시적 강제변환은 코드만 봐도 의도적으로 타입변환이 일어난다는 사실을 알 수 있을 경우를 말하고 반대로 암시적 강제변환은 다른 작업 중 부수 효과로 타입 변환이 일어나는 경우이다. 즉, 타입 변환이 일어난다는 사실이 눈에 보이지 않는다.
const a = 13;
const b = String(a); // 명시적 강제변환
const c = a + ""; // 암시적 강제변환
먼저 강제변환을 이해하려면 값이 문자열, 숫자, 불리언 등의 타입을 가지게 되는 추상 연산을 이해해야 한다.
문자열이 아닌 값을 문자열로 바꾸는 변환 작업은 ToString 추상 연산 로직이 담당한다.
내장 원시 값은 본연의 문자열화 방법이 정해져 있다.
null → "null"
undefined → "undefined"
123 → "123"
숫자가 아닌 값을 수식 연산이 가능한 숫자로 바꾸는 변환 작업은 ToNumber 추상 연산 로직이 담당한다.
true → 1
false → 0
undefined → NaN
null → 0
문자열 값에 ToNumber를 적용할 경우에는 변환이 가능하면 숫자로 변환하고 불가능할 경우 결과는 NaN이다.
앞서 ToNumber에서 true는 1로, false는 0으로 변환이 가능하다고 했다.
그럼 반대로 ToBoolean을 이용해 1을 true로, 0을 false로 변환할 수 있지 않을까 생각할 수도 있지만 JS에서 숫자와 불리언은 서로 별개이다.
즉, 1과 true는 같은 값이 아니다.
JS에서 true/false가 아닌 값을 불리언으로 강제 변환하는 것은 두 가지 경우 중 하나에 해당한다.
1. 불리언으로 강제변환하면 false가 되는 값
2. 1번을 제외한 나머지(명백하게 true가 되는 값)
두 가지 경우 중 첫 번째에 해당하는 경우의 값들을 falsy 값이라고 한다.
위의 리스트에 있는 값들은 불리언으로 변환 시 false의 값을 가진다.
그외에는 무조건 true의 값을 가진다.
String()이나 Number()는 알겠는데 +, -는 생소할 수 있다.
여기서 +나 -는 단항 연산자로 피연산자를 숫자로 강제변환한다.
++
parseInt()는 숫자 형태의 문자열을 파싱한다.
즉, 좌 → 우 방향으로 문자열을 파싱하다 숫자 같지 않은 문자를 만나면 파싱을 멈춘다.
반면 강제 변환은 숫자 같지 않은 문자를 만나면 NaN을 반환한다.const a = "13px"; Number(a); // NaN parseInt(a); // 13
! 부정 단항 연산자는 값을 불리언으로 강제변환하는데 이 과정에서 truthy와 falsy가 뒤바뀐다.
따라서 부정 단한 연산자를 두번 사용한 !! 이중 부정 연산자를 사용한다.
+ 연산자는 숫자의 덧셈도 가능하고 문자열의 접합도 가능하다.
숫자 + 숫자 라면 숫자의 덧셈을, 문자열 + 문자열 이라면 문자열의 접합을 하겠지만 숫자 + 문자열 의 경우에는 둘 중 어떤 연산을 할 지 바로 대답하기 어렵다.
ES5 명세에 따르면, + 알고리즘은 한쪽 피연산자가 문자열이거나 문자열 표현형으로 나타낼 수 있을 경우 문자열 접합 연산을 수행한다.
즉, 숫자 + 문자열의 경우 한쪽 피연산자가 문자열이기 때문에 결과는 문자열이 되는 것이다.
const a = 13;
const b = a + "";
console.log(b); // "13"
반대로 - 연산자는 숫자의 뺄셈만 가능하다.
따라서 피연산자가 무엇이든 숫자로 강제변환한 뒤 숫자의 뺄셈 연산을 수행한다.
const a = 13;
const b = a - "";
const c = String(a) - 3;
console.log(b); // 13
console.log(c); // 10
비 불리언이 불리언으로의 암시적 강제 변환이 일어나는 경우는 다음과 같다.
이러한 경우에 해당하면 ToBoolean 추상 연산 규칙에 따라 불리언 값으로 강제변환된다.
여기서 짚고 넘어가야 할 점은 ||(논리 OR 연산자)와 && (논리 AND 연산자)의 결괏값이 불리언이 아니라는 점이다.
두 연산자 모두 계산 과정에서 좌측 피연산자가 불리언 값으로 변환되지만 연산의 결괏값은 두 피연산자의 값들 중 하나이다.
즉, 양자택일이다.
|| 연산자는 첫 번째 피연산자를 불리언으로 강제변환했을 때 그 결과가 true면 첫 번째 피연산자의 값을, false면 두 번째 피연산자의 값을 반환한다.
반대로 && 연산자는 true면 두 번째 피연산자의 값을, false면 첫 번째 피연산자의 값을 반환한다.
const a = 13;
const b = null;
console.log(a && b); // null
console.log(a || b); // 13
console.log(b && a); // null
console.log(b || a); // 13
우리 스터디에서는 각 파트를 읽고 문제를 만든다.
아래는 내가 만들었던 문제인데 한번쯤은 생각해봐도 좋을 것 같다.
+와-연산이 이루어지는 과정을 설명해 주세요.- 출력될 값을 적고 이유를 설명해 주세요.
const a = 42; const b = null; const c = ""; console.log(a && b && c);