[Effective JavaScript] 세미콜론 삽입 법칙

김범식·2023년 6월 15일
0

Effective JavaScript

목록 보기
19/33
post-thumbnail

자바스크립트의 편리함 중 하나는 문장을 종료하는 세미콜론을 생략할 수 있다는 점이다. 그러나 암묵적인 강제 형변환과 비슷하게 세미콜론 삽입에는 함정이있다. 세가지가 있는데 이제부터 알아보자

1. 세미콜론은 한 줄 이사의 새로운 행이나, 프로그램 입력의 마지막이나 } 토큰 전에만 삽입된다.

세미콜론은 줄의 마지막 부분, 블록의 마지막 부분, 또는 프로그램의 마지막 부분에서만 생략이 가능하다. 따라서 다음은 아무런 문제없는 함수다.

//정상
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}

2. 세미콜론은 다음 입력 토큰을 파싱할 수 없을 때에만 삽입된다.

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 키워드 다음에 오는 새루운 행은 자동 세미콜론 삽입을 강제한다.

다음과 같은 경우에도 동일한 세미콜론 삽입 규칙이 적용된다.

  • throw 선언문
  • 명시적인 이름표가 있는 break나 continue 선언문
  • ++나 — 연산자 접미어
a
++
b

이 코드는 다음과 같이 파싱된다.

a; ++b;

++연산자는 접두어가 될 수도 있고 접미어가 될 수 도 있지만 새로운 행에 뒤이어 접미어로 위치할 수 없다.

3. 세미콜론은 for 반복문의 구분자나 빈 선언문으로 절대 삽입되지 않는다.

이 규칙은 간단하게 말해서 for 루프의 머리 부분에 반드시 명시적으로 세미콜론을 포함해야 한다는 뜻이다.

for( var i = 0, total = 1 // 파싱 오류남
	i < n
	i++ ){
	total *= i
}

이와 비슷하게 본문이 비어있는 루프도 명시적인 세미콜론이 필요하다.

function infiniteLoop(){ while(true)} //파싱오류
function infiniteLoop() {while(true);} // O

기억할 점

  • 세미콜론은 } 앞이나 줄의 마지막 또는 프로그램의 마지막 전에만 추론되어 삽입된다.
  • 세미콜론은 다음 토큰이 파싱될 수 없을 때에만 추론되어 삽입된다.
  • 선언문이 (, [, +, -, / 으로 시작할 때는 절대 세미콜론을 생략하면 안된다.
  • 스크립트를 병합할 때, 스크립트들 사이에 명시적으로 세미콜론을 삽입하라.
  • return, throw, break, continue, ++, — 바로뒤에 새로운 행을 입력하지 마라.
  • for 반복문 머리 부분에서는 세미콜론이 구분자 또는 빈 선언문으로도 절대 추론되어 삽입되지 않는다.
profile
frontend developer

0개의 댓글