JavaScript 입문 | 함수 | 함수의 유효 범위 (function scope)

함수의 유효 범위 (function scope)

대부분의 프로그래밍 언어에서는 블록 내에서 정의된 변수를 블록 외부에서는 접근할 수 없다.
블록(block)이란 코드 내에서 중괄호({})로 둘러싸인 부분을 가리킨다.
이러한 블록을 기준으로 하는 유효 범위를 블록 단위의 유효 범위라고 한다.

하지만 자바스크립트는 다른 언어와는 달리 함수를 블록 대신 사용한다.
자바스크립트에서 함수는 자신이 정의된 범위 안에서 정의된 모든 변수 및 함수에 접근할 수 있다.

‘전역 함수’는 모든 전역 변수와 전역 함수에 접근할 수 있다.
반면, 다른 함수 내에 정의된 ‘내부 함수’는 그 함수의 부모 함수(parent function)에서 정의된 모든 변수 및 부모 함수가 접근할 수 있는 모든 다른 변수까지도 접근할 수 있다.

// x, y, name을 전역 변수로 선언함.
var x = 10, y = 20;
// sub()를 전역 함수로 선언함.
function sub() {
    return x - y;     // 전역 변수인 x, y에 접근함.
}
document.write(sub() + "<br>");
// parentFunc()을 전역 함수로 선언함.
function parentFunc() {
    var x = 1, y = 2; // 전역 변수와 같은 이름으로 선언하여 전역 변수의 범위를 제한함.
    function add() {  // add() 함수는 내부 함수로 선언됨.
        return x + y; // 전역 변수가 아닌 지역 변수 x, y에 접근함.
    }
    return add();
}
document.write(parentFunc());

함수 호이스팅(hoisting)

자바스크립트에서 함수의 유효 범위라는 것은 함수 안에서 선언된 모든 변수는 함수 전체에 걸쳐 유효하다는 의미이다.

그런데 이 유효 범위의 적용이 변수가 선언되기 전에도 똑같이 적용된다.
이러한 자바스크립트의 특징을 함수 호이스팅(hoisting)이라고 한다.
즉, 자바스크립트 함수 안에 있는 모든 변수의 선언은 함수의 맨 처음으로 이동된 것처럼 동작한다.

var globalNum = 10;     // globalNum을 전역 변수로 선언함.
function printNum() {
    document.write("지역 변수 globalNum 선언 전의 globalNum의 값은 " + globalNum + "이다.<br>"); // ①
    var globalNum = 20; // globalNum을 지역 변수로 선언함. // ②
    document.write("지역 변수 globalNum 선언 후의 globalNum의 값은 " + globalNum + "이다.<br>");
}
printNum();

위의 예제 ①의 시점에서는 변수 globalNum가 전역 변수를 가리킨다고 생각하기 쉽다.
하지만 자바스크립트 내부에서는 함수 호이스팅에 의해 다음과 같이 코드가 변경되어 처리된다.

호이스팅 후의 코드

var globalNum = 10;
function printNum() {
    var globalNum; // 함수 호이스팅에 의해 변수의 선언 부분이 함수의 맨 처음 부분으로 이동됨.
    document.write("지역 변수 globalNum 선언 전의 globalNum의 값은 " + globalNum + "이다.<br>");
    globalNum = 20;
    document.write("지역 변수 globalNum 선언 후의 globalNum의 값은 " + globalNum + "이다.<br>");
}
printNum();

위의 예제 ①의 시점에서는 globalNum라는 지역 변수가 선언만 되어 있고, 아직 초기화만 안 된 상태이다.
따라서 이때 globalNum 변수에 접근하면 아직 초기화되지 않은 변수에 접근했으므로, undefined 값을 반환하게 된다.
실제로 변수가 초기화되는 시점은 원래 코드에서 변수가 선언된 ②의 시점이다.

자바스크립트에서는 함수 호이스팅이 자동으로 수행되지만, 항상 함수 블록의 첫 부분에 변수를 선언하는 것이 좋다.