본문 바로가기
프론트엔드 개발

클로저 (Closure)

by jyamin 2021. 10. 7.
728x90

“A closure is the combination of a function and the lexical environment within which that function was declared.”
클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.

 

클로저의 정의

MDN에서 정의하고 있는 클로저(Closure)이다.

위 정의에서 말하는 “함수”란 반환된 내부 함수를 의미하고 “그 함수가 선언될 때의 렉시컬 환경(Lexical environment)”란 내부 함수가 선언됐을 때의 스코프를 의미한다. 즉, 클로저는 반환된 내부 함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수다.

자바스크립트에서는 모든 함수가 자연스럽게 클로저가 된다. 코드에서 변수에 접근할 때는 먼저 내부 렉시컬 환경을 검색 범위로 잡는데, 내부 렉시컬 환경에서 원하는 변수를 찾지 못하면 검색 범위를 내부 렉시컬 환경이 참조하는 외부 렉시컬 환경으로 확장한다. 이 과정은 검색 범위가 전역 렉시컬 환경으로 확장될 때까지 반복된다. 내부 함수가 유효한 상태에서 외부 함수가 종료되어 외부 함수의 실행 컨텍스트가 반환되어도, 외부 함수 실행 컨텍스트 내 변수, 함수 선언 등의 정보를 가지고 있다. 외부 함수의 이러한 정보들은 내부 함수에 의해 참조되는 한 유효하여 내부 함수가 스코프 체인을 통해 참조할 수 있다.

// ex1)

function getClosure() {

  let favourite = "blue" // : 2

  function color () {

            console.log(favourite) // : 1

  }

  return color

}

 

let closure = getClosure() // : 3

console.log(closure()) // blue : 4

 

1. 함수 `color`는 `favourite`를 찾아서 출력한다. 2. 함수 `color`의 내부 렉시컬 환경에 `favourite`가 없으므로, 외부 렉시컬 환경인 `getClosure` 함수로 확장하여 검색한다. 3. 함수 `color`를 글로벌 스코프에서 `closure`라고 선언했다. 4. 내부 함수인 `color`가 본인의 렉시컬 스코프를 벗어나, 글로벌에서 `closure`라는 이름으로 호출했고, `blue`라는 값이 출력된다.

내부 함수 color를 보았을 때, 자신을 포함하고 있는 외부 함수 getClosure 보다 오래 유지되고 있다. 외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역 변수에 접근할 수 있는데 이러한 함수 를 클로저(Closure)라고 부른다.

클로저의 활용

const makeCounter = (predicate) => {

  let counter = 0

  return function () {

     counter = predicate(counter)

     return counter

  }

}

 

const increase = (n) => {

    return ++n

}

 

const decrease = (n) => {

    return --n

}

 

const increaser = makeCounter(increase)

console.log(increaser()) // 1

console.log(increaser()) // 2

 

const decreaser = makeCounter(decrease)

console.log(decreaser()) // -1

console.log(decreaser()) // -2

 

외부 함수 makeCounter는 안에 있는 함수는 클로저(Closure)다. 자신이 생성되었을 때의 렉시컬 환경인 makeCounter의 스코프에 있는 변수 counter외부 함수 makeCounter는를 기억하고 있다가, 밖에서 호출되었을 때 스코프를 기억하고 counter에 접근하기 때문이다.

함수 makeCounter를 호출해서 새로 만든 함수를 반환할 때, 반환된 함수는 각각의 독립된 렉시컬 환경을 갖는다. decreaser 함수와 increaser 함수의 counter 상태가 연동되지 않는 이유이기도 하다.

728x90

'프론트엔드 개발' 카테고리의 다른 글

웹 렌더링 (Rendering on the Web)  (0) 2021.10.15
URI?? URL??  (0) 2021.10.08
React-Hooks : useState 연습하기  (0) 2021.10.08
Module not found: Can't resolve 'xxx'  (0) 2021.07.24
타입스크립트를 사용해야 하는 이유  (0) 2021.07.19

댓글