출처 : MDN
클로저를 이해하려면, 어휘적 범위 지정 Lexical scoping을 이해해야 한다
function init() {
var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
function displayName() { // displayName() 은 내부 함수이며, 클로저다.
alert(name); // 부모 함수에서 선언된 변수를 사용한다.
}
displayName();
}
init();
init()은 지역변수 name과 내부 함수 displayName()을 생성한다
내부 함수 displayName()은 외부 함수의 변수 name에 접근할 수 있다
만약 displayName 내부에도 name이라는 변수를 가지고 있었다면, this.name을 사용하여 외부 함수의 변수에 접근했을 것
위 예시는 함수가 중첩된 상황에서 파서가 어떻게 변수를 처리하는지 알 수 있으며, 어휘적 범위 지정 Lexical Scoping의 한 예이다
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
//myFunc변수에 displayName을 리턴함
//유효범위의 어휘적 환경을 유지
myFunc();
//리턴된 displayName 함수를 실행(name 변수에 접근)
자바스크립트는 함수를 리턴하고, 함수는 클로저를 형성
클로저는 함수와 함수가 선언된 어휘적 환경의 조합
이 환경은 클로저가 생선된 시점의 유효 범위 내의 모든 지역 변수로 구성된다
function makeAdder(x) {
var y = 1;
return function(z) {
y = 100;
return x + y + z;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
//클로저에 x와 y의 환경이 저장됨
console.log(add5(2)); // 107 (x:5 + y:100 + z:2)
console.log(add10(2)); // 112 (x:10 + y:100 + z:2)
//함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산
add5, add10은 둘 다 클로저이다
같은 함수 정의를 공유하지만, 서로 다른 어휘적 환경을 가진다
다른 몇몇 언어들은 private으로 선언할 수 있는 기능을 제공한다. 하지만 JavaScript의 경우 제공되지 않는 기능이기에, 클로저를 통해 흉내낼 수 있다.
var counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
};
})();
위 예시에서 private은 privateCounter
변수와 changeBy
함수이다.
private 하다 함은.. 외부에서 직접적인 접근이 불가능하여, 반환된 increment
,decrement
,value
를 통해서만 접근이 가능하다.
이러한 방법은 객체지향 프로그래밍의 정보 은닉과 캡슐화 같은 특징, 이점들을 얻을 수 있다.
var counter1 = counter();
var counter2 = counter();
alert(counter1.value()); /* 0 */
counter1.increment();
counter1.increment();
alert(counter1.value()); /* 2 */
counter1.decrement();
alert(counter1.value()); /* 1 */
alert(counter2.value()); /* 0 */
위와 같이 counter1
,counter2
서로 다른 두개의 카운터를 만들 수도 있으며, 각 카운터는 독립성을 유지한다.
var
키워드로 작성되어, 만약 더 중첩된 클로저를 사용할 경우 문제가 있을 수 있다. let
키워드를 사용하여 스코프 범위를 한정하여 사용하자