JavaScript 클로저(Closure)

표정민·2020년 6월 19일
2
post-thumbnail

JavaScript 클로저(Closure)에 대하여 알아보도록 하자.

🥠 클로저(Closure)란?

MDN에서는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다고 정의하고 있다.


🥠 정적 유효범위(Lexical scope)

스코프(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)가 정해져 있기 때문이다.


🥠 클로저 스코프 체인(Closure scope chain)

모든 클로저에는 세가지 스코프(범위)가 있다

  1. 지역 범위 (Local Scope, Own scope)
  2. 외부 함수 범위 (Outer Functions Scope)
  3. 전역 범위 (Global 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 리스트의 마지막 요소를 가리키고 있을 것이다.

이경우 해결 책은 아래와 같이 사용하면 된다.

  1. 함수 팩토리 사용
  2. 익명 클로저를 사용
  3. ES2015의 let 키워드를 사용

참조

https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures

0개의 댓글