다음 예제를 보자.
function object(a, b){
var x = 10;
var innerFunc = function(innerParam){ console.log((a + b) / (innerParam + x))};
return innerFunc;
}
var pointer = object(2, 4);
pointer(2);
책에 보면 클로저를 설명하기 위해 실행 컨텍스트, 변수 객체, 스코프 체인, 스코프 프로퍼티 등등 처음보면 이해하기 어려운 내용들이 마구마구 나오게 된다.
이런 개념들을 알면 좋지만 몰라도 위 예제를 쉽게 이해할 수 있게 설명해보겠다.
전역 컨텍스트에서 object(2, 4)함수를 호출해 pointer 변수에 담고 pointer를 실행하고 있다. 하나 하나씩 나눠서 보도록 하자.
object(2, 4)는 2와 4를 파라미터로 넘기기까지 한 함수(객체)이고 함수 내부에서 변수 x, innterFunc만 담은 함수(객체)라고 생각하자. 함수도 객체다. 그리고 object(2, 4)을 pointer 변수에 담는데 pointer변수에 위 객체의 메모리 주소를 담는 것이다. C언어를 배운 사람이라면 pointer 변수가 포인터 역할을 한다고 이해할 수 있을 것이다.
pointer 변수에 (2)를 붙여 호출한다.
결과값이 어떻게 될까?
우선 object 함수 a, b 파라미터는 2, 4로 넘어가고 pointer(2)를 실행할 때 x에는 10, innerParam에 2값을 넘김으로써 console창에는 (2 + 4) / (2 + 10), 즉 0.5가 표시된다.
여기서 pointer(2)를 실행하기 전까지 pointer는 object() 안에 innerFunc를 계속해서 참조하고 있다. 함수객체니까 리턴값을 참조하고 있는 것이다.
C언어에서 포인터를 배운 사람이라면 클로저를 금방 이해할 수 있을 것이다.
그럼 클로저를 사용할 때 유의해야 할 사항들을 알아보자.
다음 예제를 보자.
function object(param){
var num = param;
return function(x){
num += x;
console.log('num: ' + num);
}
}
var pointer = object(40);
pointer(5);
pointer(-10);
pointer 변수는 파라미터로 40을 넘기는 object함수 객체를 가리키고 있다. 같은 곳을 포인터로 가리키고 있는 것이다. 그러므로 pointer 변수를 계속 실행하면 num값이 계속해서 변한다.
다음 유의해야할 경우를 보자.
function object(){
var x = 1;
return {
func1 : function(){ console.log(++x)},
func2 : function(){ console.log(--x)}
};
};
var pointer = object();
pointer.func1();
pointer.func2();
반환되는 객체에 두 개의 함수가 정의되어 있는데, 두 함수가 모두 같은 변수 x를 참조한다. 그래서 각각의 함수를 호출할 때마다 x 값이 변화한다.
다음으로 루프 안에서 클로저를 사용할 때 주의할 점이다.
function countingSec(x){
for (var i = 1; i <= x; i++){
setTimeout(function(){
console.log(i);
}, i + 1000)
}
}
countingSec(3);
이 함수를 실행하면 1, 2, 3이라고 출력될 것 같다. 하지만 결과는 4만 연속 3번 출력된다. 왜냐하면 setTimeout에 들어가는 함수가 i를 참조하는데 이 함수가 실행되는 시점은 countingSec함수 실행이 종료된 이후이고, i 값은 이미 4가 된 상태이기 때문이다.
그렇다면 1, 2, 3으로 출력되게 하려면 어떻게 해야 할까?
function countingSec(x){
for (var i = 1; i <= x; i++){
(function(thisI){
setTimeout(function(){
console.log(thisI);
}, thisI * 1000);
}(i))
}
}
countingSec(3);
즉시 실행 함수를 실행시켜 i값을 thisI에 복사해서 setTimeout 함수에 넘겨주면 원하는 결과를 얻을 수 있다.
'Programming > JavaScript' 카테고리의 다른 글
[JavaScript] 객체 리터럴 방식과 생성자 함수로 만든 객체의 차이 (0) | 2020.07.18 |
---|---|
[JavaScript] this 바인딩 (0) | 2020.07.07 |
[JavaScript] 자바스크립트 함수 기본 (0) | 2020.07.04 |