본문 바로가기

[JS] 클로저

[JS] 클로저

📝 Summary

  • 클로저는 함수와 그 함수 주변의 상태의 주소 조합이다.
  • 클로저의 함수는 어디에서 호출되느냐와 무관하게 선언된 함수 주변 환경에 따라 접근할 수 있는 변수가 정해진다.

 

JavaScript에서는 다른 컴퓨터 언어와는 조금 다른 특성을 종종 가지고 있는데, 그 중 클로저라는 개념에 대해서 알아보자. MDN의 클로저 정의는 다음과 같다.

"함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다."

특이하게도 자바스크립트는 함수가 호출되는 환경과 별개로 기존에 선언되어 있던 환경, 즉 어휘적 환경을 기준으로 변수를 조회하려고 한다. 이와 같은 이유로 "외부 함수의 변수에 접근할 수 있는 내부 함수"를 클로저 함수라고 한다.


1️⃣ 클로저란?

closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). - mdn (2023)

 

클로저는 함수와 그 함수 주변의 상태의 주소 조합이다.

다시 말해, 클로저는 함수와 그 함수가 접근할 수 있는 변수의 조합이다.


2️⃣ 클로저를 어떻게 구분할 수 있을까?

그렇다면 아래 코드에서는 무엇이 클로저일까?

const globalVar = '전역 변수';

function outerFn() {
  const outerFnVar = 'outer 함수 내의 변수';
  const innerFn = function() { 
    return 'innerFn은 ' + outerFnVar + '와 ' + globalVar + '에 접근할 수 있습니다.';
  }
	return innerFn;
}

위 코드에 있는 함수부터 찬찬히 살펴보면

  1. 함수 outerFn에서는 변수 globalVar에 접근할 수 있다.
  2. 함수 innerFn에서는 변수 globalVar와 함수 outerFn 내부의 outerFnVar에 접근할 수 있다.

즉, 위 코드에서 클로저는 두 조합을 찾을 수 있다.

  1. 함수 outerFn과 outerFn에서 접근할 수 있는 globalVar
  2. 함수 innerFn과 innerFn에서 접근할 수 있는 globalVar, outerFnVar


3️⃣ 클로저는 왜 중요할까?

변수의 접근 범위인 스코프와 비슷한 개념인데, 왜 따로 클로저만 구분을 할까? 클로저의 함수는 어디에서 호출되느냐와 무관하게 선언된 함수 주변 환경에 따라 접근할 수 있는 변수가 정해지기 때문이다. 

 

const globalVar = '전역 변수';

function outerFn() {
const outerFnVar = 'outer 함수 내의 변수';
const innerFn = function () {
return (
'innerFn은 ' + outerFnVar + '와 ' + globalVar + '에 접근할 수 있습니다.'
);
};
return innerFn;
}

const innerFnOnGlobal = outerFn();
const message = innerFnOnGlobal();  
console.log(message);
 

innerFnOnGlobal은 outerFn 내부의 innerFn의 주솟값을 가진다. 그다음 줄에서 innerFnOnGlobal을 호출()한다. 이때, innerFnOnGlobal은 innerFn 밖에 있기 때문에 outerFnVar에는 접근하지 못한다고 생각할 수 있는데, 실제로는 접근할 수 있다.

 

왜 접근할 수 있을까? innerFn 함수가 최초 선언되었던 환경에서는 outerFnVar에 접근할 수 있기 때문이다. innerFnOnGlobal은 innerFn의 주솟값을 가지고 있고, innerFn은 클로저로서 outerFnVar에 접근할 수 있기 때문이다. 이 “환경”을 어휘적 환경(Lexical Environment)라고 한다.

 

코드를 직접 실행해보면  'innerFn은 outer 함수 내의 변수와 전역 변수에 접근할 수 있습니다.' 라는 문자열이 리턴되어 message 변수에 담겨 로그로 출력된다. 만약 클로저가 JavaScript에 없는 개념이라면, outerFnVar에 접근할 수 없어 에러가 났을 것이다.

 

디버거에서도 아래와 같이 클로저이기 때문에 접근할 수 있었던 outerFnVar는 따로 분류하고 있는 모습을 확인할 수 있다.

실제 클로저를 사용할 때는 outerFn, innerFn처럼 함수가 함수를 리턴하는 패턴을 자주 사용하고, outerFn을 외부 함수, innerFn을 내부 함수라고 통칭한다.

// 클로저 사용 패턴 1
function outerFn() {
  const outerFnVar = 'outer 함수 내의 변수';
  const innerFn = function() { 
    return 'innerFn은 ' + outerFnVar + '에 접근할 수 있습니다.';
  }
	return innerFn;
}

문제풀이

 

다양한 실험들 

** return / return 

-> 잘 작동한다 

 

 

 

 

** const 변수 / return 함수 

-> 변수만 정의하는 것이기 때문에 결과값 변화가 없어 보인다

 

 

 

 

 

 

** const 변수 / return 변수 

-> 퀴즈에 나오는 예시처럼 memolog는 innerFn의 스코프에 있기 때문에 접근이 불가하다. 

728x90
⬆︎