JavaScript | 클로저 (Closure)

📌 어휘적 환경 (Lexical Environment)

JS는 어휘적 환경을 갖는다.

🔹 원리 (예시 1)

◾ 목표

코드가 위 → 아래 까지 어떻게 동작하는지 파악


1. 코드 실행

코드가 실행되면

스크립트 내에서 선언한 변수들이 어휘적 환경 (Lexical Environment) 에 올라감

  • let 으로 선언된 변수
    • 호이스팅 됨.
    • 초기화 x → 사용 불가
  • 함수 선언문
    • 바로 초기화 → 사용 가능 (함수 표현식은 이렇게 못함)

2. 코드 1번째 줄

  • let one 을 만남.

  • one

    아직 할당 안되어 있음. → 초기값 undefined를 가짐 → 사용 가능

3. 코드 2번째 줄

  • one 에 1이 할당됨
  • 함수 선언은 초기에 이미 완료 → 마지막 라인으로 가서 함수 실행됨.

4. 마지막 줄

  1. 순간, 새로운 어휘적 환경 (Lexical Environment) 생성

  • 이 곳에 저장되는 것

    함수가 넘겨받은 매개변수 & 지역 변수들

  1. 함수가 호출되는 동안, 2개의 Lexical 환경 을 가짐.

  • 내부 Lexical 환경 (함수에서 만들어진)

    • 외부 Lexical 환경 에 대한 참조를 가짐.

      현재, 이 함수의 외부 Lexical 환경전역 Lexical 환경

  • 전역 Lexical 환경 (외부에서 받은)


  • 코드에서 변수를 찾을 때, 넓히는 범위 순서

    내부부터 찾음. 없으면 → 외부, 없으면 → 전역 Lexical 환경

    • 현재 코드
      1. 우선 내부 Lexical 환경 에서 찾음 ( one & num )

        num은 찾았지만 one이 없음

      2. 외부로 넓혀서 있는지 찾음

        찾음 → 더해줌

🔹 원리 (예시 2)

function makeAdder(x){
  return function(y){
    return x + y
  }
}

const add3 = makeAdder(3)
console.log(add3(2))
  • makeAdder : add 함수를 만들어주는 함수

1. 최초 실행

makeAdder 함수 & 변수 add3 : 전역 Lexical 환경에 들어감.

  • add3

    • 초기화 안된 상태
    • 사용 불가

2. 변수 add3 라인 실행

  • makeAdder 실행 & makeAdder Lexical 환경 만들어짐

    • 전달받은 x의 값이 들어감
    • 함수의 Lexical 환경 에 저장되는 것 넘겨받은 매개변수 & 지역 변수들
  • add3 (전역 Lexical 환경 에 있던)

    이 함수가 실행되었으니, return 하는 함수가 됨.


3. 마지막 줄 실행

  1. add3 을 실행하면 (익명)함수가 실행되는데 이 때 또 Lexical 환경 이 만들어짐.

    이번엔 y가 2로 들어감

  2. x+y 하기

    1. 처음에는 익명함수 Lexical 환경 에서 x와 y를 찾음

      y는 있는데 x는 없음

    2. 참조하는 외부 Lexical 환경 (makeAdder) 으로 감

      x를 찾음


4. 정리

  • Closure

    이런 것을 Closure라고 함.

    Closure는 함수와 그 함수의 렉시컬 환경의 조합이다.

    • 함수가 생성될 당시의 외부 변수를 기억하고 생성된 이후에도 그 변수에 계속 해서 접근이 가능한 기능인 것

    • 외부 함수의 실행이 끝나서 외부 함수가 소멸된 이후에도 내부 함수가 외부 함수의 변수에 접근 가능

  • makeAdder(10)이 호출되지만, add3에는 변화 없음.

    add10add3은 서로 다른 환경을 가지고 있는 것

🔹 예시 3

function makeCounter() {
  let num = 0; // 외부 함수의 변수. 은닉화.
  
  return function() { // 익명 함수 
    return num++
  }
}

const counter = makeCounter();

console.log(counter()) // 0
console.log(counter()) // 1
console.log(counter()) // 2

◾ 흐름

  1. counter에 익명함수(makeCounter가 리턴하는 함수)를 넣음.

    익명함수는 숫자(외부 함수의 변수) 반환

  2. 실행 시

    초기값 0. 한 번 더하면 1이 증가한 1, 2 이 나옴

    내부 함수에서 외부함수의 변수(num)에 접근한 것

◾ 결론

생성(const counter = makeCounter();)된 이후에 계속 기억하고 있다는 것.

◾ 숫자 수정 가능 여부 & 은닉화

  • 숫자들 (0, 1, 2) 수정

    불가능

  • 은닉화 성공

    오직 counter를 증가시키고 반환받기 때문에.

    갑자기 99로 바꾸기 or 100씩 증가시키기 → 불가능


참고

  • 코딩앙마_자바스크립트 중급

좋은 웹페이지 즐겨찾기