자바스크립트 완벽가이드 5장 (문장)

문장(statement), 즉 ‘문’은 자바스크립트 문장, 다시 말해 명령이다. 자바스크립트 문장은 세미콜론(;)으로 끝난다. 표현식은 어떤 값을 생성하기 위해 평가되지만, 구문은 어떤 일을 하기위해 실행되는 것이다.

5.2 복합문과 빈 문장

문장 블록은 여러 문장을 하나의 복합문으로 묶는다. 자바스크립트에는 블록 단위의 유효범위(scope)가 존재하지 않기 때문에, 구문 블록 안에 선언된 변수는 블록뿐 아니라 블록 밖에서도 접근할 수 있다.

자바스크립트 문법은 대체로 하나의 하위문을 허용한다. 예를 들어, while 루프 문법은 루프 몸체로 하나의 문장을 허용한다. 문장 블록을 사용하면 문법이 허용하는 하나의 하위문 자리에 얼마든지 많은 문장을 넣을 수 있다.

결과적으로 복합문은 자바스크립트 문법에서 하나의 문장이 있어야 할 곳에 여러 문장을 사용할 수 있게 한다. 빈문장은 정 반대다. 하나의 문장이 있어야 할 곳에 아무런 문장도 두지 않을 수 있도록 한다. 빈 문장은 ;을 사용하여 표현한다. 임의로 빈 문장을 사용할 경우에는, 코드에 고의로 사용했다는 설명을 주석으로 표시하는 것이 좋다.


5.3 선언문

5.3.1 var

var문은 하나 또는 그 이상의 변수를 선언한다. var문에서 변수에 초기 값을 지정하지 않으면 변수의 초기 값은 undefined가 된다. 스크립트나 함수 안에서 선언된 변수는 해당 스크립트나 함수 전체에 걸쳐 유효하다. 하지만 초기화된 var문이 선언된 시점에서 발생하고, 그 전까지는 변수 값은 undefined가 된다.

5.3.2 function

함수 선언문은 자바스크립트 최상위 단계 코드에서 나타날 수도 있고, 다른 함수 내에 중첩될 수도 있다. 하지만 함수가 다른 함수 속에 중첩될 때는, 중첩된 함수 내에서 최상위 단계에 위치해야 한다. 즉, 함수 선언은 if문이나 while문 등의 다른 문장 안에 있을 수 없다.

함수 선언문은 함수 이름을 포함한다는 점에서 함수 정의표현식과는 차이가 있다. 둘 다 새 함수 객체를 만들지만, 함수 선언문은 함수 이름을 변수로 선언한 후 이 변수에 함수 객체를 할당한다는 차이가 있다. var로 선언한 변수와 같이, 함수 선언문으로 정의된 함수는 스크립트나 함수 유효범위 최상단에 위치하게 되어(hoisted) 해당 유효범위 내에서 사용할 수 있다. var 문을 이용하면 변수 선언만 유효범위 최상단으로 끌어올려지지만(변수 초기화 코드는 원래 위치에 그대로 유지), 함수 선언문을 이용하면 함수의 이름과 본문 모두 유효범위 최상단으로 끌어올려진다. 이때 스크립트 내의 모든 함수 또는 함수의 중첩 함수는 다른 코드가 실행되기 전에 선언된다. 이는 자바스크립트 함수를 호출하는 코드가 선언문이 나오기 전에도 올 수 있다는 뜻이다.


5.4 조건문

5.4.1 if

대다수의 프로그래밍 언어와 마찬가지로 자바스크립트 규칙에 의하면 else 절은 기본적으로 가장 가까운 if문에 속한다. 모하함을 없애고 읽기 쉽고 이해하기 쉬운 동시에 유지보수와 디버깅을 쉽게 하려면 반드시 중괄호를 사용해야 한다.

5.4.3 switch

switch문은 if문에서처럼 동일한 표현식이 여러 번 반복되는 문제점을 확실히 해결한다. 다음은 실용적인 switch 문의 예제이다. 이 예제에서는 어떤 값을 문자열로 바꾸는데, 그 값의 타입에 따라 각기 다른 방법을 적용해 문자열로 변환한다.

1
2
3
4
5
6
7
8
9
10
function convert(x) {
switch(typeof x) {
case 'number': // 주어진 숫자를 16진수 정수로 변경한다.
return x.toString(16);
case 'string': // 문자열을 큰따옴표로 묶어서 반환한다.
return '"' + x + '"';
default: // 이 외의 타입은 문자열로 변환한다.
return String(x);
}
}

switch문이 실행될 때마다 모든 case 표현식이 매번 평가되지는 않기 때문에, case 표현식에 함수 호출이나 값 할당과 같이 부수 효과를 일으킬 수 있는 표현식을 사용해서는 안된다. 가장 안전한 방법은 case 표현식을 상수 표현식만으로 제한하는 것이다. case를 판별할 때는 동치 연산자 ==가 아닌 일치 연산자 ===가 사용된다.


5.5 루프

자바스크립트에는 네 개의 루프문이 있다.

  1. while
  2. do/while
  3. for
  4. for/in

5.5.4 for/in

for/in문은 for 키워드를 사용하지만, 일반적인 for 루프와는 전혀 다른 종류다.

1
2
for (변수 in 객체)
문장

‘변수’는 보통 변수 이름이지만 좌변 값으로 평가되는 표현식이거나, 단일 변수를 선언하는 var문일 수도 있다. ‘객체’는 객체로 평가되는 표현식이어야 한다. ‘문장’은 루프 몸체를 구성하는 문장 또는 문장 블록이다.
일반적인 for 루프를 사용하면 다음과 같이 배열의 원소를 쉽게 순회할 수 있다.

1
2
for(var i = 0; i < a.length; i++)
console.log(a[i]);

이와 비슷하게 for/in 루프를 사용하면 객체가 가진 프로퍼티들을 쉽게 순회할 수 있다.

1
2
3
for(var p in o) {       // 변수 p에 객체 o가 가진 프로퍼티 이름을 할당한다.
console.log(o[p]);
}

for/in문을 실행하기 위해서 자바스크립트 인터프리터는 먼저 객체 표현식을 평가한다. 이때 표현식이 null이나 undefined로 평가되면 인터프리터는 해당 루프를 중단하고 다음 문장을 실행한다. 만약 표현식이 원시 값으로 평가되면 해당 값은, 값과 상응하는 Wrapper 객체로 바뀐다. 이 외에 표현식은 객체로 평가된다.

for/in 루프에서 사용하는 ‘변수’로는 할당 표현식의 좌변에 적합한 무언가로 평가되는 임의의 표현식을 사용할 수 있다. 이 표현식은 루프가 돌 때마다 평가되는데, 이때 매번 다르게 평가될 수 있다. 다음과 같은 코드를 사용하면 주어진 객체의 모든 프로퍼티 이름을 배열에 복사할 수 있다.

1
2
3
var o = {x:1, y:2, z:3};
var a = [?], i = 0;
for(a[i++] in o) /* 비어 있음 */;

자바스크립트 배열은 단순히 특별한 종류의 객체에 지나지 않는다. 따라서 for/in 루프는 객체의 프로퍼티와 마찬가지로 배열 인덱스 또한 하나씩 열거할 수 있다.

for/in 루프는 실제로 객체가 가진 모든 프로퍼티를 열거하지 않고 오직 ‘열거 할 수 있는 프로퍼티’만 열거한다. 자바스크립트 코어에 정의된 다양한 내장 메서드들은 일반적으로 열거할 수 없다. (예를 들면 toString() 메서드)


5.6 점프문

5.6.4 return

함수를 호출하는 것 역시 표현식이고, 모든 표현식에는 값이 있다. return문은 함수 호출 표현식의 값, 즉 함수에서 반환하는 값을 지정하는 데 쓰인다. return문은 오직 함수 몸체 내부에서만 나타날 수 있다. 다른 곳에서 사용하면 문법 에러가 발생한다. return문이 실행되면 ‘표현식’이 평가되어 그 결과가 함수의 값으로 반환된다. 함수 내에 return문이 없다면 함수 호출은 단지 함수 몸체의 끝에 도달할 때까지 모든 구문을 차례로 실행하고, 호출한 지점으로 돌아간다. 이 경우에 해당 함수 호출 표현식의 값은 undefined가 된다. return문은 주로 함수의 마지막에 위치하지만 반드시 마지막에 있어야 하는것은 아니며, 함수 몸체 내에서 return문이 실행되면 아직 남은 문장들이 있어도 함수를 호출한 지점으로 돌아간다.

5.6.5 throw

자바스크립트에서는 런타임 에러가 일어날 때마다 예외를 발생시킨다. Error 객체는 에러의 종류를 담고 있는 name 프로퍼티와 Error 클래스 생성자 함수에 넘기는 문자열 값을 담고 있는 message 프로퍼티를 갖고 있다.

예외가 발생하면 자바스크립트 인터프리터는 정상적인 프로그램 실행을 즉시 중단하고 가장 가까운 예외 처리기로 넘어간다. 예외를 발생시킨 코드 블록이 catch절과 연결되어 있지 않으면, 인터프리터는 바로 상위 단계를 감싸고 있는 코드 블록에 연결된 예외 처리기가 있는지 확인한다. 이 과정은 처리기를 찾을 때까지 계속된다. 이같은 방법으로 자바스크립트의 언어적인 구조를 따라서, 즉 호출 스택을 따라서 예외가 전파되어 올라간다. 예외 처리기를 찾을 수 없는 경우 해당 예외는 에러로 취급되고 사용자에게 보고된다.

5.6.5 try/catch/finally

  • try : 단순히 예외가 발생할지도 모르는 코드 블록을 정의하는 역할
  • catch : try 블록 내부에서 예외가 발생할 경우 호출되는 문장 블록
  • finally : try 블록에서 일어난 일에 관계없이 항상 실행이 보장되어야 할 뒷정리용 코드가 포함

정상적인 경우에, 자바스크립트 인터프리터는 try 블록의 끝까지 도달하고 난 후, finally 블록으로 이동해 무언가 필요한 뒷정리를 수행한다. 만일 인터프리터가 return, continue, break 문 등을 만나 try 블록의 제어를 벗어날 경우, 새 지점으로 이동하기 전에 finally 블록이 실행된다.

만일 예외를 처리할 catch 블록이 없다면 인터프리터는 일단 finally 블록을 실행한 후 상위 블록으로 예외를 전파하여, 해당 예외를 처리할 수 있는 가장 가까운 catch 절로 이동한다.


5.7 기타

5.7.1 with

with문은 유효범위 체인의 첫 번째에 ‘객체’를 추가한다. 그 후에 ‘문장’을 실행한 다음, 유효범위 체인을 ‘객체’를 추가하기 전 상태로 되돌려 놓는다. with문을 사용하는 자바스크립트 코드는 최적화하기 힘들고 with문을 사용하지 않는 코드에 비해 느리기 때문에 사용하지 않는것이 좋다.

5.7.2 debugger

debugger문은 평소에는 아무것도 하지 않지만 디버거 프로그램을 사용할 수 있고 디버거가 실행 중일 때, 자바스크립트 구현체는 해당 위치에서 정의된 코드 디버깅을 수행한다. debugger문은 코드의 중단점(breakpoint)와 같이 동작한다. 자바스크립트 코드의 실행을 잠시 멈추고 디버거 프로그램을 사용해 변수의 값을 출력할 수 있고, 호출 스택등을 살펴볼 수 있다.

5.7.3 “use strict”

'use strict'는 ECMAScript 5에서 처음 소개된 지시어다. ‘use strict’ 지시어를 사용하는 목적은 지시어 다음에 오는 (스크립트나 함수의) 코드들이 엄격 모드를 따르게 하기 위해서다. 스크립트의 최상단에 ‘use strict’ 지시어가 있으면 최상단(함수가 아닌) 코드는 엄격한 코드(엄격 모드를 따르는 코드)다.

엄격한 코드는 엄격 모드에서 실행된다. ECMAScript 5의 엄격 모드는 언어의 일부 기능이 제한된 부분 집합으로, 몇 가지 주용한 언어적 문제점을 수정하고 강력한 에러 검사와 향상된 보안 기능을 제공한다. 다음과 같은 부분이 일반 모드와 다르다.

  • with문은 엄격 모드에서 사용 불가능 하다.
  • 엄격 모드에서 모든 변수는 반드시 선언되어야 한다. 선언되지 않은 변수나 함수, 함수 인자, catch 절 인자, 전역 객체 프로퍼티에 값을 할당하는 경우 ReferenceError 예외가 발생한다.
  • 엄격 모드에서 함수는 메서드로 호출된 것이 아닌, 함수로 호출된 함수의 this 값은 undefined다. (표준 모드에서는 함수가 함수로 호출될 때 항상 전역 객체를 this의 값으로 넘겨주게 된다.) 또한 엄격 모드에서는 함수를 call()이나 apply()로 호출하면, this의 값은 정확히 call()이나 apply() 함수의 첫 번째 인자 값으로 설정된다. (표준 모드에서는 null과 undefined 값은 전역 객체로 대체되고, 객체가 아닌 값들은 객체로 바뀌게 된다.)
  • 엄격 모드에서 함수의 arguments 객체는 함수에 전달된 값의 정적 사본을 갖고 있지만 표준 모드에서 arguments 배열의 원소와 함수의 전달인자는 동일한 값을 참조한다.



출처 : “JavaScript: The Definitive Guide, by David Flanagan (O’Reilly). Copyright 2011 David Flanagan, 978-0-596-80552-4”

댓글

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×