JavaScript 클로저(Closure)에 대하여 알아보도록 하자.
MDN에서는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다
고 정의하고 있다.
스코프(scope)는 함수를 호출할 때 결정되는 것이 아니라 함수를 선언할 때 정해진다.
아래 예제를 살펴보자
function makeFunc() {
var name = "pyo jung min";
function displayName() {
console.log(name);
}
return displayName;
}
var myFunc = makeFunc();
//myFunc변수에 displayName을 리턴함
//유효범위의 어휘적 환경을 유지
myFunc();
//리턴된 displayName 함수를 실행(name 변수에 접근)
오류가 발생할 것 같지만 'pyo jung min'이 오류 없이 출력되는 것을 확인할 수 있다.
이는 함수 호출 이전에 함수 선언 시 이미 정적 유효범위(Lexical scope)가 정해져 있기 때문이다.
모든 클로저에는 세가지 스코프(범위)가 있다
따라서, 우리는 클로저에 대해 세가지 범위 모두 접근할 수 있지만, 중첩된 내부 함수가 있는 경우 종종 실수를 저지른다.
아래 예제를 확인해보자
// 전역 범위 (global scope)
var e = 10;
function sum(a){
return function(b){
return function(c){
// 외부 함수 범위 (outer functions scope)
return function(d){
// 지역 범위 (local scope)
return a + b + c + d + e;
}
}
}
}
console.log(sum(1)(2)(3)(4)); // log 20
// 익명 함수 없이 작성할 수도 있다.
// 전역 범위 (global scope)
var e = 10;
function sum(a){
return function sum2(b){
return function sum3(c){
// 외부 함수 범위 (outer functions scope)
return function sum4(d){
// 지역 범위 (local scope)
return a + b + c + d + e;
}
}
}
}
var s = sum(1);
var s1 = s(2);
var s2 = s1(3);
var s3 = s2(4);
console.log(s3) //log 20
위의 예제를 보면 일련의 중첩된 함수들을 확인할 수 있다. 이 함수들은 전부 외부 함수의 스코프에 접근할 수 있다. 그런데 문제는 즉각적인 외부 함수의 스코프만을 추측한다는 것이다. 이 문맥에서는 모든 클로저가 선언된 외부 함수의 스코프에 접근한다라고 말할 수 있다.
변수 선언을 var로 할시 클로저와 관련된 일반적인 문제는 루프 안에서 클로저가 생성되었을 때 발생한다.다음 예제를 보자.
error case의 경우 루프에서 세 개의 클로저가 만들어졌지만 각 클로저는 값이 변하는 변수가 (item.help) 있는 같은 단일 환경을 공유한다. onfocus 콜백이 실행될 때 콜백의 환경에서 item 변수는 (세개의 클로저가 공유한다) helpText 리스트의 마지막 요소를 가리키고 있을 것이다.
이경우 해결 책은 아래와 같이 사용하면 된다.
참조
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures