'당신이 놓친 자바스크립트' 시리즈는 모던 Javascript 튜토리얼를 공부하며 필자가 자바스크립트에 대해 몰랐던 점이나 헷갈렸던 점들을 정리한 시리즈입니다. 모든 출처는 위 사이트에 있습니다.
본 포스팅에서는 이전 포스팅에 이어서 자바스크립트 기본 문법 중에서 쉽게 놓칠 수 있는 부분들을 다룹니다.
alert( '01' >= 1 ); // true. '01'을 1로 형변환
alert( true < 0 ); // false. true를 1로 형변환
alert( '31' > true ); // true. '31'을 31로 형변환, true를 1로 형변환
alert( null > 0 ); // false
alert( null == 0 ); // false. null이 0으로 형변환 된다면 true여야 한다.
alert( null >= 0 ); // true
console.log( null || 0 || 1 ); // 1
console.log( undefined || 0 || null ); // 0. 모두 falsy이므로, 마지막 값인 null을 그대로 반환한다.
// true. alert 함수는 실행되지 않음.
console.log( true || alert("not printed") );
// undefined. alert 함수가 실행되며, 반환 값이 명시되지 않은 함수는 자동으로 undefined를 리턴한다.
console.log( false || alert("printed") );
// true. alert 함수가 undefined를 리턴하므로, alert 함수가 실행된 후 두 번째 피연산자인 true가 리턴됨.
console.log( alert("printed") || true );
console.log( 1 && 0 ); // 0
console.log( 1 && 5 ); // 5
// undefined. alert 함수가 호출되면 falsy한 값을 리턴하므로, 연산자가 true까지 도달하지 않는다.
console.log( alert("printed") && true );
null 병합 연산자 ??는 '값이 확정되어 있는 변수'를 찾을 때 사용합니다. 자바스크립트에서 undefined는 값이 할당되지 않았음을 의미하고, null은 값이 비어있음을 의미하죠. 따라서, a ?? b
라는 구문은 a가 undefined도 아니고 null도 아니라면 a를 리턴하고, 그 외에는 b를 리턴합니다.
즉, 위 구문을 풀어서 쓰면 다음과 같을 것입니다.
(a !== null && a !== undefined) ? a : b;
null 병합 연산자는 0과 같은 falsy값이 저장될 수 있는 변수를 평가할 때 매우 유용하게 쓰일 수 있습니다. 하지만, 추가된지 얼마 되지 않은 문법이기 때문에 일부 구형 브라우저에서는 호환되지 않습니다. 특히, IE(인터넷 익스플로러)에서는 아예 지원되지 않습니다.
null 병합 연산자는 안정성 관련 이슈로 인해, 괄호 없이는 &&나 ||와 함께 사용할 수 없습니다.
따라서, 아래와 같이 반드시 괄호와 함께 사용되어야 합니다.
let i = 100;
do {
alert( i ); // alert(100)이 한 번 실행됨.
i++;
} while (i < 0); // 조건은 이미 false이다.
(i > 5) ? alert(i) : break; // 문법 에러 발생
레이블(label)은 반복문 앞에 콜론과 함께 쓰이는 식별자입니다. 원래 break나 continue와 같은 반복문 지시자들은 해당 지시자가 포함되어있는 가장 가까운 반복문 한 개만을 제어할 수 있습니다. 하지만, 반복문 지시자들을 레이블과 함께 사용하면, 반복문의 중첩 수와 상관 없이 특정 반복문 한개를 선택하여 제어할 수 있습니다.
예를 들어, 다음과 같이 두 개의 반복문이 중첩되어 있을 때, 내부 반복문에서 break 지시자를 레이블과 함께 사용하여 중첩된 반복문 전체를 빠져나올 수 있습니다.
// 외부 반복문에 outer라는 레이블을 붙임.
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`(${i},${j})의 값`, '');
// 사용자가 아무것도 입력하지 않거나 Cancel 버튼을 누르면 두 반복문 모두를 빠져나옵니다.
if (!input) break outer;
}
}
alert('완료!');
let sum = 0;
function anotherFunction() {
return sum;
}
function showMessage(from, number = anotherFunction()) {
console.log(number);
sum++;
}
showMessage(); // 0
showMessage(); // 1
return
(some + long + expression + or + whatever * f(a) + f(b))
----- 위 코드는 다음과 같이 해석됩니다. -----
return;
(some + long + expression + or + whatever * f(a) + f(b))
----- 따라서, 다음과 같이 작성해야 합니다. -----
return (
some + long + expression
+ or +
whatever * f(a) + f(b)
)
// 함수 선언
function sayHi() {
alert( "Hello" );
}
// 함수 표현식
let sayHi = function() {
alert( "Hello" );
};
자바스크립트에서 함수는 값입니다. 따라서, 함수를 값처럼 취급할 수 있기 때문에 함수를 변수에 저장할 수 있으며, 다른 변수에 함수를 복사하는 것도 가능합니다.
특이한 점은, 함수를 호출하는 것이 아니라 함수 그 자체를 출력한다면 함수의 소스 코드가 문자열로 형변환되어 출력된다는 것입니다. 따라서, 다음과 같은 이상한 코드도 정상적으로 동작합니다.
함수 선언으로 정의된 함수는, 호이스팅 시 함수 전체가 최상단에 위치하게 됩니다.
console.log("hi");
function sum(a, b) {
return a + b;
}
----- 호이스팅 이후 -----
function sum(a, b) {
return a + b;
}
console.log("hi");
이와 달리, 함수 표현식으로 정의된 함수는 호이스팅 시 함수를 저장할 변수 선언만 최상단에 위치하게 되고, 변수에 함수를 할당하는 부분은 위치가 그대로 유지됩니다.
console.log("hi");
let sum = function(a, b) {
return a + b;
};
----- 호이스팅 이후 -----
let sum;
console.log("hi");
sum = function(a, b) {
return a + b;
}
이로 인해, 함수 표현식을 사용했을 때에는 함수가 정의되기 전에 함수 호출을 할 시 다음과 같은 에러가 발생할 수 있습니다.