소년코딩

클로저(closure): 이미 생명주기가 끝난 외부 함수의 변수를 참조하는 함수

function outer() {
    var name = 'oppa';
    var f = function() {
        console.log(name);
    }
    return f;
}
var inner = outer();
/* outer()의 실행 컨텍스트가 끝났습니다. */

inner();    // 'oppa'

outer()의 실행 컨텍스트는 사라졌지만 outer() 의 활성 객체는 inner스코프 체인으로 참조되어 있다.

이것이 바로 자바스크립트에서 구현한 클로저라는 개념이다.

 

클로저로 참조되는 외부 변수 즉, outer의 name과 같은 변수를 자유 변수라고 한다.

호이스팅

이러한 클로저의 특성을 바탕으로 자바스크립트에서는 함수형 프로그래밍이 가능하다.


1. 함수의 캡슐화

캡슐화란 정보은닉의 개념으로, 해당 정보를 외부로 노출시키지 않는 것이다.

ex ) "I am XXX. I live in XXX. I am XX years old"라는 문장을 출력하는데, 나머지 부분 고정되어 수정할 수 없고, XX 부분은 사용자에게 인자로 입력받아 값을 출력하는 함수

만약 다른 함수에서 배열에 쉽게 접근하여 값을 바꾸고, 또 실수로 같은 이름의 변수를 만들면 버그가 생길 수 있다.

이러한 가능성을 대비하기 위해 클로저를 활용하여 배열을 추가적인 스코프에 넣고 사용하는 방법이다.

var getStr = (function() {
     var buffAr = [
          'I am ',
          '',
          '. i live in ',
          '',
          '. I am ',
          '',
          ' years old.'
     ];
 
     return (function(name, city, age) {
          buffAr[1] = name,
          burrAr[3] = city,
          buffAr[5] = age,
 
          return buffAr.join('');
     });
})();
 
var str = getStr('oppacoding', 'Seoul', 25);
console.log(str);     // "I am Hong. I live in Seoul. I am 25 years old"

변수 getStr에 익명 함수를 즉시 실행시켜 반환되는 함수를 할당했다.

이 반환되는 함수가 클로저가되고, 이 클로저는 자유 변수 buffArr을 스코프 체인에서 참조할 수 있다.


2. 주의사항

루프 안에서 클로저를 활용할 때는 주의해야 한다.

클로저는 항상 외부 함수의 변수에 마지막으로 저장된 값만 알 수 있다.

클로저가 특정 변수가 아니라 전체 변수 객체에 대한 참조를 저장하기 때문이다. 

ex) 1,2,3을 1초 간격으로 출력하는 함수

function countSeconds(num) {
     for(var i = 1; i <= num; ++i) {
          setTimeout(function () {
               console.log(i);
          }, i * 1000);
     }
};
 
countSeconds(3);
 
// 결과 => 4가 연속 3번 1초 간격으로 출력

setTimeout 함수의 인자로 들어가는 함수는 자유 변수 i를 참조한다.

하지만 이 함수가 실행되는 시점은 countSeconds() 함수의 실행이 종료된 이후이고, i의 값은 이미 4이다.

 

원하는 결과를 얻기 위해서는 루프 i값 복사본을 함수에 넘기는데 즉시 실행 함수를 사용해야한다.

function countSeconds(num) {
     for(var i = 1; i <= num; ++i) {
          (function (currentI) {
               setTimeout(function() {
                    console.log(currentI);
               }, currentI * 1000);
          }(i));
     }
};
 
countSeconds(3);       
 
// 결과 => 1, 2, 3 을 1초 간격으로 출력

 

자바스크립트

by 소년코딩

추천은 글쓴이에게 큰 도움이 됩니다.

악플보다 무서운 무플, 댓글은 블로그 운영에 큰 힘이됩니다.

댓글 로드 중…

블로그 정보

소년코딩 - 소년코딩

소년코딩, 자바스크립트, C++, 물리, 게임 코딩 이야기

최근에 게시된 이야기