모던 자바스크립트 Deep Dive - 24장

박상은·2021년 10월 3일
0

요약

1. 클로저

클로저의 사전적 정의는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다
내가 이해한 바로 쉽게 바꿔보면 함수와 그 함수 외부에 선언된 변수와의 관계를 의미한다.

예시를 들어보면

function outer(){
  const v = 100;
  
  return function inner(){
    console.log(v);
  }
}

// 1
const innerFunc = outer();
// 2
innerFunc();	// 10

클로저를 알기전에 위 예시를 자세히 살펴보면 이상하다고 느낄만한 부분이 존재한다.

함수는 분명 종료되면 실행 컨텍스트 스택에서 제거되는데 그렇다면 함수내부에서 선언한 변수인 v도 없어져야하는데 1에서 함수가 끝나고 나서 2에서 v를 사용하는데 정상적으로 출력이 된다는 것이다.

이 이유에 대해서 천천히 정리해보려고 한다.

2. 클로저 이해를 위한 사전 지식

2.1 렉시컬 스코프

자바스크립트는 기본적으로 렉시컬 스코프(정적 스코프)를 따른다.
이 말의 의미는 함수선언시 그 함수의 스코프가 결정된다는 의미이다.

function testFunc1(){
  const v = 10;
  testFunc2();
}

function testFunc2(){
  console.log(v);
}

testFunc1();	// Error v is not define

위 예시를 처음볼 때 필자는 10이 출력될거라고 예상했다.
하지만 오류가 나는데 이유는 렉시컬 스코프를 따르기 때문이다.
즉, testFunc1(), testFunc2()를 선언하는 시점에 자신의 스코프가 결정되어버리기 때문에 testFunc2()를 어디서 호출하든 상관없이 전역변수로 v가 존재하지않는 이상 에러가 나는 것이 당연하다.

2.2 [[Environment]]

렉시컬 스코프에서 함수의 스코프가 결정할 때 그 함수의 스코프의 참조를 저장하는 내부슬롯이다.
좀 더 정확하게 말하면 현재 실행중인 실행 컨텍스트의 렉시컬 환경을 가리키는 값을 넣는 내부슬롯이다.

함수들은 [[Environment]]내부슬롯을 가지며 렉시컬 환경에 대한 참조값을 저장한다.

2.3 렉시컬 환경

상위스코프 즉, 자신이 정의된 스코프라고 생각하면 된다.

2.4 일급객체

일급객체는 4가지 조건을 만족하는 객체이다.
4가지중 한 가지인 함수를 반환값으로 사용할 수 있다를 만족해야 클로저가 존재할 수 있다.

2.5 가비지 컬렉터

가비지 컬렉터가 메모리할당을 해제하는 기준을 해당 식별자에 접근할 수 있는 식별자가 존재하는 여부에 의해 결정된다.

3. 클로저 예시와 이해

맨 처음 예시를 다시 가져와서 정리해보겠다.

function outer(){
  const v = 100;
  
  return function inner(){
    console.log(v);
  }
}

// 1
const innerFunc = outer();
// 2
innerFunc();	// 10
  • inner()의 렉시컬 환경은 outer()이며, outer()는 함수를 반환하는 일급객체이다.

  • 1에서 outer()가 종료되면 실행 컨텍스트 스택에서 outer()가 제거되지만 outer()의 실행 컨텍스트가 제거되는 것은 아니다.
    그리고 가비지 컬렉터에 의해서 할당이 해제되지도 않는데 그 이유는 outer()의 반환값인 inner()outer()내부에서 선언한 변수를 사용하고 있기 때문에 outer()의 실행 컨텍스트는 메모리할당해제대상에서 제외되기 때문이다.

  • 2에서 inner()를 호출할 때 inner()[[Environment]]를 이용해서 렉시컬 환경에 대한 참조를 얻어서 outer()의 변수 v에게 접근이 가능한 것이다.

이런 inner()함수와 그 바깥에 존재하는 v변수를 사용하는 함수를 클로저라고 정의한다.
즉, 이렇게 외부 변수를 사용하는 inner()함수를 클로저라고 부른다.
그리고 이 때 v변수를 자유변수라고 부른다

0개의 댓글