자바스크립트의 편리함 중 하나는 문장을 종료하는 세미콜론을 생략할 수 있다는 점이다. 그러나 암묵적인 강제 형변환과 비슷하게 세미콜론 삽입에는 함정이있다. 세가지가 있는데 이제부터 알아보자
세미콜론은 줄의 마지막 부분, 블록의 마지막 부분, 또는 프로그램의 마지막 부분에서만 생략이 가능하다. 따라서 다음은 아무런 문제없는 함수다.
//정상
function square(x){
var n = +x
return n*n
}
function area(r) { r = +r; return Math.PI*r*r}
function add1(x) {return x+1}
//오류
function area(r) { r = +r return Math.PI*r*r}
a = b
(f()); //f() 나 (f())나 동일함
다음과 같은 하나의 선언으로도 문제 없이 실행될 수 있다.
a = b(f());
즉 세미콜론은 삽입되지 않는다
반대로 다음코드를 살펴보자
a = b
f();
이 예제는 두개의 구분된 선언으로 파싱된다. 왜냐하면 다음과 같이 파싱하는 것은 오류이기 때문이다.
a = b f();
즉 다음줄의 초기 토큰이 이전 선언의 연장선으로 해석될 수 있다면, 세미콜론을 생략해선 안된다. 정확히는 (
, [
, +
, -
, /
를 조심해야한다.
다음줄이 다위의 다섯개중 하나로 시작한다면 세미콜론은 추가되지 않을 것이다.
a = b
['r','g','b'].forEach(function(key){
background[key] = foreground[key]/2;
});
위코드는 다음과 같이 파싱된다.
a = b['r','g','b'].forEach(function(key){
background[key] = foreground[key]/2;
});
대괄호 표현식이 약간 이상하게 보일 수 있지만, 자바스크립트는 쉼표로 구부된 표현식을 허용한다는 사실을 기억하라,. 이표현식은 왼쪽부터 오른쪽으로 평가되고 그 마지막 하위 표현식을 반환한다. 이 경우 문자열 ‘b’를 반환한다.
/Error/i.test(str) && fail();
이 선언문은 대소문자를 구분하지 않고 문자열을 테스트하는 정규 표현식이다. 일치되는 문자를 발견하면 fail 함수를 호출한다. 하지만 이 코드가 다음과 같이 종료되지 않은 할당문 뒤에 이어나올 수 있다.
a = b
/Error/i.test(str) && fail();
이 코드는 다음과 같이 파싱된다.
a = b/Error/i.test(str) && fail();
/
가 나눗셈 연산자로 파싱된다.
다음 두 코드도 다른결과를 나타내게 된다.
a = b //세미콜론이 추론되어 삽입됨
var x //세미콜론이 추론되어 삽입됨
(f()) //세미콜론이 추론되어 삽입됨
var x //세미콜론이 추론되어 삽입됨
a = b //세미콜론이 삽입되지 않음
(f()) //세미콜론이 추론되어 삽입됨
때문에 다음과 같은 방법을 사용하기도 한다.
var x
a = b
;(f())
이제 var x 선언을 위로 올려도 프로그램이 변경되지 않으므로 안전하다.
이런 오류는 스크립트 병합에도 문제를 발생시킨다.
//file1.js
(function(){
//...
})
//file2.js
(function(){
//...
})
두파일이 하나의 파일로 병합된다면
//file1.js
(function(){
//...
})(function(){
//...
})
다음과 같은 의도치 않은 병합이 발생하고 만다.
만약 첫선언토큰이 (
, [
, +
, -
, /
이 다섯개중 하나라면 모든 파일에 다음과 같은 방어적인 세미콜론을 접두어로 넣어 사용하여 병학문제로부터 보호할 수 있다.
//file1.js
;(function(){
//...
})
//file2.js
;(function(){
//...
})
자바스크립트 파싱오류로 판명되지 않더라도 강제적으로 세미콜론을 삽입하는 경우가 있다. 이것들을 소위 자바스크립트 문법의 제한된 생성(restricted production)이라고 부르는데, 두 토큰 사이에 새로운 행이 허용되지 않는다는 의미다.
이경우는 return 선언문의 강제 세미콜론 삽입니다.
return
{};
다음 선언문은
return {} ; // X
return ; // O
{}
;
return 키워드 다음에 오는 새루운 행은 자동 세미콜론 삽입을 강제한다.
다음과 같은 경우에도 동일한 세미콜론 삽입 규칙이 적용된다.
a
++
b
이 코드는 다음과 같이 파싱된다.
a; ++b;
++연산자는 접두어가 될 수도 있고 접미어가 될 수 도 있지만 새로운 행에 뒤이어 접미어로 위치할 수 없다.
이 규칙은 간단하게 말해서 for 루프의 머리 부분에 반드시 명시적으로 세미콜론을 포함해야 한다는 뜻이다.
for( var i = 0, total = 1 // 파싱 오류남
i < n
i++ ){
total *= i
}
이와 비슷하게 본문이 비어있는 루프도 명시적인 세미콜론이 필요하다.
function infiniteLoop(){ while(true)} //파싱오류
function infiniteLoop() {while(true);} // O
(
, [
, +
, -
, /
으로 시작할 때는 절대 세미콜론을 생략하면 안된다.