Closure에 대해서

Typescript

Posted by jopemachine on November 18, 2021 Updated on September 25, 2022

Closure에 대해서

  • 아래 함수는 클로저를 리턴한다.
1
2
3
4
5
6
7
8
9
10
11
12
const returnClosure = () => {
  let _state;

  return () => {
    if (!_state) _state = 1;
    else {
      ++_state;
    }

    return _state;
  };
}

은닉, 캡슐화

  • closure는 객체 지향으로 말하자면, _state를 private 변수로 갖는 (은닉, 캡슐화) 객체 느낌으로 생각할 수 있다.

  • 즉, closure는 상태를 갖는 함수이다.

1
const closure1 = returnClosure();
  • returnClosure가 실행될 때 closure라는 함수가 생성 (리턴) 된다.

  • closure 함수가 생성될 때 전역에 있는 맵에 이 함수를 키로, 이 함수의 Lexical scope (상태) 를 값으로 레코드를 만들어 저장한다.

  • returnClosure가 다시 실행되면 새 클로저가 생성된다. 이 함수의 _state는 이전의 _state와 아무 관계 없는 새 클로저의 상태이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 클로저가 구현되어 있지 않다면 _state는 closure 함수가 종료될 때 사라지니
// 스코프에서 찾지 못해 Reference Error를 내거나, 매번 실행될 때 마다 1이어야 한다.
console.log(closure1()); // 1
console.log(closure1()); // 2
console.log(closure1()); // 3
console.log(closure1()); // 4

const closure2 = returnClosure();

// closure2는 closure1과는 다른 Lexical scope를 갖는 함수이다. 
// 그러므로 다시 1에서 시작함!
console.log(closure2()); // 1
console.log(closure2()); // 2
console.log(closure2()); // 3
console.log(closure2()); // 4

스코프 체인

  • 아래처럼 클로저를 중첩해서 쓸 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// returnClosureClosure는 Outer 클로저를 리턴하는 Inner 클로저를 리턴
const returnClosureClosure = () => {
  let _outer_state;

  // _outer_state을 상태로 갖는 Outer closure를 리턴
  return () => {
    let _inner_state;

    if (!_outer_state) {
      _outer_state = 1;
    } else {
      ++_outer_state;
    }

    // _outer_state와 _inner_state를 모두 상태로 갖는 Inner closure를 리턴
    return () => {
      if (!_inner_state) {
        _inner_state = 1;
      } else {
        ++_inner_state;
      }

      return {
        'outer': _outer_state,
        'inner': _inner_state
      }
    };
  }
};

const returnClosure = returnClosureClosure(); // { 'outer': 0, 'inner': 0 }

let closure1;
closure1 = returnClosure(); // { 'outer': 1, 'inner': 0 }
closure1 = returnClosure(); // { 'outer': 2, 'inner': 0 }

console.log(closure1()); // { 'outer': 2, 'inner': 1 }
console.log(closure1()); // { 'outer': 2, 'inner': 2 }
console.log(closure1()); // { 'outer': 2, 'inner': 3 }