자바스크립트의 클로저

대부분의 작업을 함수를 사용하여 처리하면서도 함수형 언어도 아니고 대부분이 객체이지만 클래스도 없다. 자바스크립트는 정말로 이상하게 동작한다. 함수에 함수를 전달하는 방식은 처음에는 이상하지만 자주 사용하다 보니 편하다. C 언어에서 함수 포인터를 함수 인자로 넘겨서 호출할 수 있지만, 함수만 연결된다. 이와 다르게 자바스크립트는 수행할 함수를 전달할 때 수행 환경도 같이 전달할 수 있다. 클로저라고 한다. 클로저와 비동기 동작은 궁합이 잘 맞는다. 자바는 버전 8부터 클로저를 지원한다고 한다. 내가 이해하는 방식을 정리했다.

function test() {
  var fs = require('fs');
  var outerScopeMessage = 'not found';
  fs.readFile('index.html', 'utf8', function (error, data) {
    if(error) {
      console.log(outerScopeMessage);
    }
  });
  console.log('test ok');
}
test();

함수 한개를 선언하고 실행했다. index.html 파일을 읽으려고 fs.readFile 함수를 호출한다. 3번째 인자로 전달한 함수는 파일 읽기가 종료되면 성공하든 실패하든 불릴 것이다. 이 함수는 에러가 있으면 메시지를 출력한다. 이상한 점은 에러가 발생했을 때 출력하는 메시지가 test 함수의 지역 변수라는 것이다. test가 수행되고 나면 outerScopeMessage는 사라져야 한다. console.log(outerScopeMessage) 문장은 실패해야 한다. 그러나 아무 문제 없이 ‘test ok’가 출력되고 이어 ‘not found’가 나타난다. 이는 fs.readFile의 3번째 인자로 전달된 함수가 클로저로 동작하기 때문이다. 이 함수는 outerScopeMessage 변수를 사용하는데 fs.readFile이 종료되기 전까지는 이 함수가 수행되지 않았으므로 그때까지 outerScopeMessage의 참조 기능을 유지 시켜준다. test 함수 밖에서 outerScopeMessage 변수를 직접 읽을 수 있는 방법은 없다. 다만, fs.readFile의 3번째 인자인 함수에서는 접근할 수 있다. 자바스크립트 엔진이 outerScopeMessage 변수에 접근이 가능하도록 유지한다. 아래와 같이 fs.readFile의 3번째 인자로 이름 있는 함수를 전달해도 결과는 같다. 클로저 동작은 함수 이름의 유무와는 상관없다.

function processError(error, data) {
  if(error) {
    console.log(outerScopeMessage);
  }
}
fs.readFile('index.html', 'utf8', processError);

클로저는 함수가 선언될 때하고 수행될 때의 변수 접근 범위를 같게 유지 시켜준다. 그래서 단순히 전달받은 함수를 호출해주는 기능과는 다르다. 비동기 응답을 받는 경우에 호출될 함수를 전달하면 이 함수는 전달할 때 접근할 수 있는 변수들을 호출될 때에도 그대로 사용할 수 있다. 참조하는 함수가 존재하는 한 접근할 수 있는 변수에 대한 메모리 해제가 지연된다. 위의 예제를 조금 변경하자.

function test() {
  var outerScopeMessage = 'not found';
  return function () {
    console.log(outerScopeMessage);
  };
}

test 함수는 이름 없는 함수를 반환한다. 자바스크립트에서 함수 이름에 ()를 붙여서 그 함수를 실행할 수 있다. 아래 처럼 사용할 수 있다. test 내부의 outerScopeMessage 변수에 직접 접근할 수 있는 방법은 없다. 다만 test 함수가 반환한 함수를 실행함으로서 간접적으로 사용할 수 있다.

test()(); // 'not found'

다른 방법으로도 사용할 수 있다.

var namedFunction = test();
namedFunction() // 'not found'

namedFunction 함수는 내부에서 outerScopeMessage 변수를 사용한다.

함수형 프로그래밍 – JavaScript
자바스크립트의 클로저

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

This site uses Akismet to reduce spam. Learn how your comment data is processed.