자바스크립트 기초 - 3
목차
1. 형변환
문자, 숫자, 논리형으로의 형 변환은 자주 일어난다.
1.1 문자형으로 형변환
무언가를 출력할 때 주로 일어난다.
String(value) 사용하면 명시적 변환이 가능하다.
1.2 숫자형으로 형변환
수학 관련 연산시 주로 일어난다.
Number(value) 사용해 형변환 할 수 있다.
| 전달받은 값 | 형 변환 후 |
|---|---|
undefined | NaN |
null | 0 |
true / false | 1 / 0 |
string | 문자열이 비었다면 0 이 되고, 오류 발생 시 NaN 이 된다. |
1.3 불린형으로의 변환
논리 연산 시 발생한다.
Boolean(value) 으로도 변환할 수 있다.
| 전달받은 값 | 형 변환 후 |
|---|---|
0, null, undefined, NaN | false |
그 외의 값 | true |
예외적인 경우
- 숫자형으로 변환 시 undefined 는 0 이 아니라 NaN 이 된다.
- 문자열 “0” 과 ” ” 같은 공백은 불린형으로 변환 시 true 가 된다.
1.4 문제풀이
"" + 1 + 0 // "10"
"" - 1 + 0 // -1
true + false // 1
6 / "3" // 2
"2" * "3" // 6
4 + 5 + "px" // "9px"
"$" + 4 + 5 // "$45"
"4" - 2 // 2
"4px" - 2 // NaN
7 / 0 // Infinity
" -9 " + 5 // "-9 5"
" -9 " - 5 // -14
null + 1 // 1
undefined + 1 // NaN
" \t \n" - 2 // -2
2. 연산자
2.1 이항 연산자 +와 문자열 연결
이항 연산자 +의 피연산자로 문자열이 전달되면, 덧셈이 아닌 문자열 병합(연결)이 일어난다.
let s = "my" + "string";
alert(s); // mystring
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
alert(2 + 2 + '1' ); // "221"이 아니라 "41"이 출력됩니다.
2.2 단항 연산자 +와 숫자형으로의 변환
덧셈 연산자 +는 이항 연산자뿐만 아니라 단항 연산자로도 사용할 수 있습니다. 숫자에 단항 덧셈 연산자를 붙이면 이 연산자는 아무런 동작도 하지 않습니다. 그러나 피연산자가 숫자가 아닌 경우엔 숫자형으로의 변환이 일어납니디.
// 숫자에는 아무런 영향을 미치지 않습니다.
let x = 1;
alert( +x ); // 1
let y = -2;
alert( +y ); // -2
// 숫자형이 아닌 피연산자가 숫자형으로 변화합니다.
alert( +true ); // 1
alert( +"" ); // 0
단항 덧셈 연산자는 짧은 문법으로 Number(…)와 동일한 일을 할 수 있게 해줍니다. 개발을 하다 보면 문자열을 숫자로 변환해야 하는 경우가 자주 생깁니다. HTML 폼(form) 필드에서 값을 가져왔는데, 그 값이 문자형일 때 같이 말이죠. 실제로 폼에서 가지고 온 값은 대개 문자열 형태입니다.
let apples = "2";
let oranges = "3";
// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변화합니다.
alert( +apples + +oranges ); // 5
// `Number(...)`를 사용해서 같은 동작을 하는 코드를 작성할 수 있지만, 더 기네요.
// alert( Number(apples) + Number(oranges) ); // 5
2.3 연산자 우선순위
연산자에는 우선 순위가 있다 ’*’ 가 ’+’ 보다 우선인 것처럼
연산자우선순위표 를 참고하자.
2.4 할당 연산자 =
할당 연산자 ”=“는 우선순위가 3으로 매우 낮다.
할당 연산자 ”=“는 값을 반환합니다.
let a, b, c;
a = b = c = 2 + 2;
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4
2.5 나머지 연산자 %
alert(8 & 3); // 2
2.6 거듭제곱 연산자 **
거듭제곱 연산자 **는 표준으로 채택된 지 얼마 안 된 연산자입니다.
자연수 b가 있을 때, a ** b는 a를 b번 곱한 값이 됩니다.
alert( 2 ** 2 ); // 4 (2 * 2)
alert( 2 ** 3 ); // 8 (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)
2.7 증가/감소 연산자
증가(increment) 연산자 ++는 변수를 1 증가시킵니다.
감소(decrement) 연산자 —는 변수를 1 감소시킵니다.
증가/감소 연산자는 변수에만 쓸 수 있습니다. 5++와 같이 값에 사용하려고 하면 에러가 발생합니다.
// 전위형(prefix form)
let counter = 1;
let a = ++counter; // (*)
alert(a); // 2
// 후휘형(postfix form)
let counter = 1;
let a = counter++; // (*) ++counter를 counter++로 바꿈
alert(a); // 1
반환 값을 사용하지 않는 경우라면, 전위형과 후위형엔 차이가 없습니다.
값을 증가시키고 난 후, 증가한 값을 바로 사용하려면 전위형 증가 연산자를 사용하면 됩니다.
값을 증가시키지만, 증가 전의 기존값을 사용하려면 후위형 증가 연산자를 사용하면 됩니다.
2.8 비트 연산자
비트 연산자(bitwise operator)는 인수를 32비트 정수로 변환하여 이진 연산을 수행합니다. 이런 비트 조작 관련 연산자는 자바스크립트뿐만 아니라 대부분의 프로그래밍 언어에서 지원합니다. 아래는 비트 연산 시 쓰이는 연산자 목록입니다.
- 비트 AND ( & )
- 비트 OR (
|) - 비트 XOR ( ^ )
- 비트 NOT ( ~ )
- 왼쪽 시프트(LEFT SHIFT) ( << )
- 오른쪽 시프트(RIGHT SHIFT) ( >> )
- 부호 없는 오른쪽 시프트(ZERO-FILL RIGHT SHIFT) ( >>> )
비트 연산이 어떻게 수행되는지 이해하려면 저수준 숫자 표현(2진 표현)에 대해 알아야 하는데, 이 연산자를 쓸 일이 거의 없기 때문에 지금 여기서 그 내용을 다루는 게 최선은 아닌 것 같습니다. 그런데도 호기심이 발동한다면 MDN의 비트 연산자 문서를 추천합니다. 진짜 이 연산자가 필요할 때 문서를 보는 게 더 실용적이지만 말이죠.
2.9 복합 할당 연산자
- +=
- *=
- /=
- -=
2.10 쉼표 연산자
쉼표(comma) 연산자 ,는 좀처럼 보기 힘들고, 특이한 연산자 중 하나입니다. 코드를 짧게 쓰려는 의도로 가끔 사용됩니다. 이런 코드를 만났을 때, 어떤 연산 결과가 도출되는지 알아야 하므로 쉼표 연산자에 대해 알아보도록 합시다. 쉼표 연산자 ,는 여러 표현식을 코드 한 줄에서 평가할 수 있게 해줍니다. 이때 표현식 각각이 모두 평가되지만, 마지막 표현식의 평가 결과만 반환되는 점에 유의해야 합니다.
let a = (1 + 2, 3 + 4);
alert( a ); // 7 (3 + 4의 결과)
쉼표 연산자는 코드 가독성에 도움이 되지 않습니다. 따라서 곰곰이 생각해 본 후, 진짜 필요한 경우에만 사용하시길 바랍니다.
3. 비교 연산자
우리는 수학 시간에 아래와 같은 다양한 비교 연산자에 대해 학습한 바 있다.
- 보다 큼/작음: a > b, a < b.
- 보다 크거나/작거나 같음: a >= b, a <= b.
- 같음(동등): a == b. 등호 =가 두 개 연달아 오는 것에 유의하세요. a = b와 같이 등호가 하나일 때는 할당을 의미합니다.
- 같지 않음(부등): 같지 않음을 나타내는 수학 기호 ≠는 자바스크립트에선 a != b로 나타냅니다. 할당연산자 = 앞에 느낌표 !를 붙여서 표시합니다.
3.1 불린형 반환
다른 연산자와 마찬가지로 비교 연산자 역시 값을 반환합니다. 반환 값은 불린형입니다.
- true가 반환되면, “긍정”, “참”, “사실”을 의미합니다.
- false가 반환되면, “부정”, “거짓”, “사실이 아님”을 의미합니다.
alert( 2 > 1 ); // true
alert( 2 == 1 ); // false
alert( 2 != 1 ); // true
let result = 5 > 4; // 비교 결과를 변수에 할당
alert( result ); // true
3.2 문자열 비교
자바스크립트는 “사전”순으로 문자열을 비교합니다. “사전편집(lexicographical)“순 이라고 불리기도 하는 이 기준을 적용하면 사전 뒤쪽의 문자열은 사전 앞쪽의 문자열보다 크다고 판단됩니다. 실제 단어를 사전에 실을 때 단어를 구성하는 문자 하나하나를 비교하여 등재 순서를 정하는 것과 같이 자바스크립트도 문자열을 구성하는 문자 하나하나를 비교해가며 문자열을 비교합니다.
alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true
예시의 ‘Z’ > ‘A’는 위 알고리즘의 첫 번째 단계에서 비교 결과가 도출됩니다. 반면, 문자열 “Glow”와 “Glee”는 복수의 문자로 이루어진 문자열이기 때문에, 아래와 같은 순서로 문자열 비교가 이뤄집니다.
G는 G와 같습니다. l은 l과 같습니다. o는 e보다 크기 때문에 여기서 비교가 종료되고, o가 있는 첫 번째 문자열 “Glow”가 더 크다는 결론이 도출됩니다. 대문자 “A”와 소문자 “a”를 비교했을 때 소문자 “a”가 더 큽니다.
3.3 다른 형을 가진 값 간의 비교
비교하려는 값의 자료형이 다르면 자바스크립트는 이 값들을 숫자형으로 바꿉니다.
alert( '2' > 1 ); // true, 문자열 '2'가 숫자 2로 변환된 후 비교가 진행됩니다.
alert( '01' == 1 ); // true, 문자열 '01'이 숫자 1로 변환된 후 비교가 진행됩니다.
불린값의 경우 true는 1, false는 0으로 변환된 후 비교가 이뤄집니다.
alert( true == 1 ); // true
alert( false == 0 ); // true
흥미로운 상황
let a = 0;
alert( Boolean(a) ); // false
let b = "0";
alert( Boolean(b) ); // true
alert(a == b); // true!
동등 비교 연산자 == 와 Boolean함수의 연산 규칙이 다르기 때문이다.
3.4 일치 연산자
동등 연산자(equality operator) ==은 0과 false를 구별하지 못합니다.
alert( 0 == false ); // true
alert( '' == false ); // true
이런 문제는 동등 연산자 ==가 형이 다른 피연산자를 비교할 때 피연산자를 숫자형으로 바꾸기 때문에 발생합니다. 빈 문자열과 false는 숫자형으로 변환하면 0이 되죠.
일치 연산자(strict equality operator) ===를 사용하면 형 변환 없이 값을 비교할 수 있습니다.
alert( 0 === false ); // false, 피연산자의 형이 다르기 때문입니다.
일치 연산자 ===가 동등 연산자 ==의 엄격한 형태인 것처럼 “불일치” 연산자 !==는 부등 연산자 !=의 엄격한 형태입니다. 일치 연산자는 동등 연산자보다 한 글자 더 길긴 하지만 비교 결과가 명확하기 때문에 에러가 발생할 확률을 줄여줍니다.
3.5 null이나 undefined와 비교하기
일치 연산자 ===를 사용하여 null과 undefined를 비교
두 값의 자료형이 다르기 때문에 일치 비교 시 거짓이 반환됩니다.
alert( null === undefined ); // false
동등 연산자 ==를 사용하여 null과 undefined를 비교
동등 연산자를 사용해 null과 undefined를 비교하면 특별한 규칙이 적용돼 true가 반환됩니다. 동등 연산자는 null과 undefined를 “각별한 커플”처럼 취급합니다. 두 값은 자기들끼리는 잘 어울리지만 다른 값들과는 잘 어울리지 못하죠.
alert( null == undefined ); // true
산술 연산자나 기타 비교 연산자 < > <= >=를 사용하여 null과 undefined를 비교
null과 undefined는 숫자형으로 변환됩니다. null은 0, undefined는 NaN으로 변합니다.
3.5.1 null vs 0
alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true
위의 비교 결과는 논리에 맞지 않습니다. (3)에서 null은 0보다 크거나 같다고 했기 때문에, (1)이나 (2) 중 하나는 참이어야 하는데 둘 다 거짓을 반환하고 있습니다.
이는 동등 연산자 ==와 기타 비교 연산자 > < >= <=의 동작 방식이 다르기 때문입니다. (1)에서 null > 0이 거짓을, (3)에서 null >= 0이 참을 반환하는 이유는 (기타 비교 연산자의 동작 원리에 따라) null이 숫자형으로 변환돼 0이 되기 때문입니다.
연산자 ==는 피연산자가 undefined나 null일 때 형 변환을 하지 않습니다. undefined와 null을 비교하는 경우에만 true를 반환하고, 그 이외의 경우(null이나 undefined를 다른 값과 비교할 때)는 무조건 false를 반환합니다. 이런 이유 때문에 (2)는 거짓을 반환합니다.
3.5.2 비교가 불가능한 undefined
undefined를 다른 값과 비교해서는 안 됩니다.
alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)
- (1)과(2)에선 undefined가 NaN으로 변환되는데(숫자형으로의 변환), NaN이 피연산자인 경우 비교 연산자는 항상 false를 반환합니다.
- undefined는 null이나 undefined와 같고, 그 이외의 값과는 같지 않기 때문에 (3)은 false를 반환합니다.
3.6 함정 피하기
위와 같은 에지 케이스를 왜 살펴보았을까요? 이런 예외적인 경우를 꼭 기억해 놓고 있어야만 할까요? 그렇지는 않습니다. 개발을 하다 보면 자연스레 이런 경우를 만나고 점차 익숙해지기 때문에 지금 당장 암기해야 할 필요는 없습니다. 하지만 아래와 같은 방법을 사용해 이런 예외 상황을 미리 예방할 수 있다는 점은 알아두시길 바랍니다.
일치 연산자 ===를 제외한 비교 연산자의 피연산자에 undefined나 null이 오지 않도록 특별히 주의하시기 바랍니다.
또한, undefined나 null이 될 가능성이 있는 변수가 >= > < <=의 피연산자가 되지 않도록 주의하시기 바랍니다. 명확한 의도를 갖고 있지 않은 이상 말이죠. 만약 변수가 undefined나 null이 될 가능성이 있다고 판단되면, 이를 따로 처리하는 코드를 추가하시기 바랍니다.
3.7 비교연산자 요약
- 비교 연산자는 불린값을 반환합니다.
- 문자열은 문자 단위로 비교되는데, 이때 비교 기준은 “사전”순입니다.
- 서로 다른 타입의 값을 비교할 땐 숫자형으로 형 변환이 이뤄지고 난 후 비교가 진행됩니다(일치 연산자는 제외).
- null과 undefined는 동등 비교(==) 시 서로 같지만 다른 값과는 같지 않습니다.
- null이나 undefined가 될 확률이 있는 변수가 > 또는 <의 피연산자로 올 때는 주의를 기울이시기 바랍니다. null/undefined 여부를 확인하는 코드를 따로 추가하는 습관을 들이길 권유합니다.
3.8 비교연산자 문제
5 > 4
"apple" > "pineapple"
"2" > "12"
undefined == null
undefined === null
null == "\n0\n"
null === +"\n0\n"
- 명백히 true입니다.
- 문자열의 비교는 사전순서가 기준이므로, false입니다.
- 두 피연산자는 문자열이므로, 사전순으로 비교가 이뤄집니다. 왼쪽 피연산자의 첫 번째 글자 “2”는 오른쪽 피연산자의 첫 번째 글자 “1”보다 큽니다.
- null과 undefined는 같습니다.
- 일치 연산자는 형도 체크합니다. 형이 다르면 false가 반환됩니다.
- (4)와 유사한 문제입니다. null은 오직 undefined와 같습니다.
- 형이 다르므로 false가 반환됩니다.