함수 유효범위와 클로저

자바스크립트 인터프리터가 함수를 호출할 경우 인터프리터는 호출 객체(활성화 객체로도 알려진)를 생성한다.

모든 함수 매개변수 및 var 문으로 선언한 지역 변수는 호출 객체 안에 정의되고 호출 객체의 프로퍼티가 된다.

다음 예제의 경우, f1 호출 객체에는 y1과 x1 프로퍼티가 담기고, f2 호출 객체에는 y2와 x2 프로퍼티가 담긴다.

function f1(y1) {
    var x1 = 1;
    function f2(y2) {
        var x2 = 2;
    }
    f2();
}
f1(); 

함수 유효범위 체인

자바스크립트 함수는 그것이 실행되고 있는 유효범위가 아니라 그것이 정의된 유효범위 내에서 실행된다.

함수를 정의하면 현재 유효범위 체인이 저장되고 해당 함수의 내부 상태의 일부를 구성하게 된다.

가장 높은 레벨의 유효범위 체인은 단순히 전역 객체로만 구성돼 있다.

중첩 함수를 정의하면 유효범위 체인이 바깥 함수를 포함하게 되어 중첩된 함수에서는 바깥 함수의 인자와 지역 변수에 모두 접근할 수 있다.

자바스크립트 인터프리터가 함수를 호출하면 해당 함수의 호출 객체는 유효범위 체인 앞에 추가된다.

다음 예제의 경우 f2가 호출되면 유효범위 체인에는 세 개의 객체가 포함되는데, 이러한 객체로는 해당 함수 자체의 호출 객체와 f1의 호출 객체, 그리고 전역 객체가 있다.

function f1(y1) {
    var x1 = 1;
    function f2(y2) {
        var x2 = 2;
    }
    f2();
}
f1(); 

자바스크립트 클로저

자바스크립트 함수는 실행될 코드와 코드가 실행되는 유효범위의 조합에 해당한다. 이러한 코드와 유효범위의 조합은 컴퓨터 과학 분야에서 클로저(closure)로 알려져 있다. 모든 자바스크립트 함수는 클로저다.

때때로 함수 호출 간에도 값을 유지할 수 있는 함수를 작성하고 싶을 때가 있다. 이를 위해 지역 변수를 사용할 수는 없는데, 호출 객체가 함수 호출 간에 유지되지 않기 때문이다. 클로저를 이용하면 영속적이고 비공개적인 변수를 만들어낼 수 있다. 다음 예제를 보자.

getUniqueID = (function(){
    var id = 0;
    return function(){ 
        return id++; 
    }
})();

console.log("id: " + getUniqueID());
console.log("id: " + getUniqueID());
console.log("id: " + getUniqueID());

위 코드를 실행한 결과는 다음과 같다.

id: 0
id: 1
id: 2

또 다른 흥미로운 예제는 다음과 같다.

function makeMultiplier(x){
    return function(y){
        return x*y;
    }
}

var multiply10 = makeMultiplier(10);
var multiply20 = makeMultiplier(20);

console.log(multiply10(5));     // 50
console.log(multiply20(5));     // 100

이 예제에서는 makeMultiplier(x)라는 함수를 정의했는데, 이 함수는 x라는 인자를 하나 받아 새로운 함수를 반환한다. 이 함수에서 반환한 함수는 y라는 인자를 받아 x*y를 반환한다.

본질적으로 makeMultiplier는 함수 팩터리다. 즉, 특정 값을 그것의 인자와 곱할 수 있는 함수를 만들어낸다. 위 예제에서는 함수 팩터리를 이용해 두 개의 새로운 함수를 만들어냈다. 하나는 인자에 10을 곱하는 함수이고, 다른 하나는 20을 곱하는 함수다.

multiply10과 multiply20은 모두 클로저다. 두 함수는 동일한 함수 본문 정의를 공유하지만 유효범위 체인은 다르다. multiply10의 유효범위 체인에서는 x가 10이다. multiply20의 경우에는 x가 20이다.

관련 수업

← 이전다음 →