조각조각 - 클로저

eocode·2024년 3월 6일
1
post-thumbnail

목차

  1. 클로저
    1.1. 클로저란?
    1.2 클로저 동작 가능 이유
    1.3 클로저 특징
    1.4 정리
  2. 참고 자료

1. 클로저

처음 클로저를 공부할 때 설명을 들어도 잘 이해가 가지 않았습니다. 그래서 클로저 이해에 도움이 되는 실행 컨텍스트, 자바스크립트 엔진 실행 과정, 변수 타입, 호이스팅, 스코프 등 많은 개념들을 먼저 공부하고 블로그 글로 정리하였습니다. 이제 이 개념들을 기반으로 클로저를 좀 더 잘이해하고 정리해보도록 하겠습니다.

1.1 클로저(Closure)란?

클로저 구조 미리보기

closure

mdn에서 자바스크립트 클로저를 함수와 함수가 선언된 어휘적 환경의 조합이라고 정의합니다. 이 정의만으로는 클로저가 무엇인지 감이 잡히지 않습니다. 뒤이어 내부 함수에서 외부 함수의 범위에 대한 접근을 제공한다고 설명이 이어집니다.

음... 아직 잘 이해가 가지 않습니다. 클로저 이해를 위해 우선 외부함수와 내부함수(중첩함수)에 대해 알아야 할것같습니다.

외부 함수, 내부(중첩) 함수

function isInnerFn() {
	console.log('나는 내부 함수가 아닙니다');
}

function outerFn() {
  let x = 10;
  
  isInnerFn()
  
  return function innerFn() {
    return x = x + 1;
  }
}
const fn = outerFn();
console.log(fn()); //11

외부 함수

위 코드의 outerFn 함수와 같이 내부에 함수 선언을 포함하고 있는 함수를 외부함수라고 합니다.

내부 함수(중첩 함수)

내부 함수는 위 코드의 innerFn 함수와 같이 특정 함수 내부에서 정의된 함수를 내부 함수라고 합니다. 이 내부 함수는 함수가 선언된 스코프의 외부에서 사용이 불가능합니다. 즉 outerFn 함수 스코프의 상위 스코프인 전역 스코프에서 innerFn 함수를 사용할 수 없습니다.

반드시 알아야 할 점은 함수 내부에서 정의된 함수만이 내부(중첩) 함수입니다. 함수 내부에서 호출되었다고 내부함수라고 하지 않습니다.
즉 위 코드에서 isInnerFn 함수는 outerFn 함수 내부에서 호출되기만 한거지 내부함수는 아닙니다.

그래서 클로저가 뭔데?

다시 돌아와서 클로저가 무엇인지 알아보겠습니다.

위에서 '내부 함수에서 외부 함수의 범위에 대한 접근을 제공한다'고하였습니다. 즉 내부 함수에서 외부 함수 변수에 접근 가능하다는 말입니다. 이는 뭐 당연한 말입니다. 이전 스코프를 정리한 게시글에서도 보았듯이 자바스크립트는 정적 스코프를 따릅니다. 따라서 변수 탐색을 위해 스코프 체이닝으로 외부 스코프로 이동할때 함수가 선언된 위치를 기준으로 외부 스코프로 이동합니다. 그렇기 때문에 내부 함수에서 외부 함수의 변수에 접근하다는 말은 너무나도 당연한 말입니다.

그렇다면 이 당연한 말을 굳이 '클로저'라고 부르는걸까요?
당연히 아닙니다. 단순히 내부 함수에서 외부 함수의 변수에 접근 가능한 것을 클로저라고 하지 않습니다.

클로저가 성립하기 위해선 내부 함수가 실행되며 동시에 외부 함수가 종료되어야 합니다. 즉 내부 함수가 그 자체로 외부함수의 리턴 값이 되어야 합니다.

function outerFn() {
  let x = 10;
  
  return function innerFn() {
    return x = x + 1;
  }
}

const fn = outerFn(); 
console.log(fn()); //11
console.log(fn()); //12
console.log(fn()); //13

내부 함수가 외부 함수의 리턴 값인 경우 어떤 일이 발생하는지 살펴보겠습니다.

변수 fn은 outerFn 함수의 리턴 값을 할당 받습니다. 즉 변수 fn은 중첩 함수 innerFn을 할당 받습니다. 따라서 변수 fn을 호출하여 중첩함수를 호출할 수 있습니다. 변수 fn으로 중첩함수 innerFn을 호출하면 11이 출력됩니다. 다시 한번 호출하면 12가 출력됩니다. 마지막으로 한번도 호출하면 13이 출력됩니다. 이상하게도 외부 함수의 변수인 x에 계속 접근이 가능하고 x의 값이 초기화되지 않고 유지되고 있습니다. 마치 outerFn 함수 실행 컨텍스트의 어휘적 환경이 계속 살아 남아있어 보입니다.

이러한 동작은 매우 이상합니다. 이전에 공부했던 실행 컨텍스트를 떠올려보면 함수 outerFn이 호출되면서 outerFn 함수 컨텍스트가 콜스택에 담깁니다. 이후 함수가 끝나고 값을 리턴하며 콜스택에서 사라집니다. 문제는 여기서 innerFn 함수를 리턴하면서 outerFn 함수가 종료된다는 것입니다. innerFn 함수를 리턴하기 때문에 이때 outerFn 함수는 종료됩되어야합니다. 즉 콜스택에서 제거되어야합니다. 그렇다면 당연히도 innerFn 함수에서 변수 x에 접근할 때 외부 스코프인 outerFn 함수 환경 레코드에 존재하는 변수 x에 접근이 불가능하고 오류가 발생해야 합니다.

그런데 코드를 보면 변수 x가 계속 살아있고 접근도 가능합니다. 바로 이러한 상황, 중첩 함수에서 사라졌어야할 외부 함수의 변수에 계속 접근 가능한 상황을 클로저라고 합니다.

클로저 특징을 정리해보면 아래와 같습니다.

  • 외부 함수와 내부(중첩) 함수가 존재한다.
  • 중첩 함수가 외부 함수의 리턴 값이다.
  • 외부 함수가 실행되면 내부 함수가 리턴되며 콜스택에서 외부 함수 실행 컨텍스트가 제거된다.
  • 콜스택에서 사라졌음에도 중첩 함수에서 외부 함수 환경 레코드에 접근이 가능하다.

1. 2 클로저 동작 가능 이유

이제 '클로저'가 무엇인지는 알았습니다. 이제 클로저가 왜 가능한건지 즉, 왜 오류가 발생하지 않고 사라진 외부 함수 환경 레코드에 접근이 가능 한 건지 이유를 알아보겠습니다. 이 이유를 알아보기 위해선 우선 함수 객체가 무엇인지와 함수 내부 슬롯, 가비지 컬렉터의 개념을 파악해야합니다.

함수 객체

함수 객체는 함수 이름과 함수 코드를 프로퍼티로 갖는 객체입니다. 일급 객체로서 값과 성질을 갖으며 변수에 할당하거나 프로퍼티나 배열의 요소가 될 수 있습니다. 또한 함수 객체는 다른 함수의 인수로 전달하거나 반환값으로 사용할 수 있습니다. 그렇기 때문에 고차 함수, 콜백 함수로 사용이 가능합니다.

일급 객체
일반적으로 적용 가능한 연산을 모두 지원하는 객체

  • 변수에 할당
  • 다른 함수의 인수로 전달
  • 다른 함수의 결과로 반환

함수 객체 생성 타이밍

코드가 실행되면 자바스크립트 엔진이 평가 단계에 돌입합니다. 이 과정에서 함수 선언 코드를 만나면 자바스크립트 엔진은 환경 레코드에 함수 식별자를 등록합니다.

이때 함수 선언 코드가 함수 선언문으로 되어 있는 경우 평가 단계에서 바로 함수 객체를 환경 레코드에 등록합니다. 반면에 함수 표현식으로 되어 있는 경우 평가 단계 완료 후 실행 단계에서 함수 선언문이 실행될 때 객체를 생성하고 환경 레코드에 등록합니다.
(🚨 함수 선언문 코드가 실행될 때 이지 함수가 호출될 때가 아닙니다!!!!)

function exampleFunction(a, b) {
  return a + b;
}

위 코드와 같은 함수 선언문 코드가 실행된다면 자바스크립트 엔진 평가 단계에서 우선 exampleFunction 식별자가 환경 레코드에 등록됩니다. 이어서 함수 선언문이기 때문에 평가 단계에서 바로 함수 객체를 생성해 환경 레코드에 저장합니다. 이때 생성되는 함수 객체는 내부적으로 아래의 프로퍼티와 메서드를 가집니다.

  • name: 함수의 이름, 이 경우 "exampleFunction"입니다.
  • length: 함수가 기대하는 인자의 수, 위 함수에서는 2입니다.
  • prototype: 함수의 프로토타입 객체를 가리키는 프로퍼티입니다. 모든 함수 객체는 prototype 객체를 가지며, 이 객체에는 생성자로 사용될 때 인스턴스가 상속받을 메서드들이 저장됩니다.
  • callapplybind: 함수를 호출하는 다양한 방법을 제공하는 메서드들입니다.
    - call : 주어진 this 값과 인자들을 가지고 함수를 호출합니다.
    - apply :  주어진 this 값과 인자 배열을 가지고 함수를 호출합니다.
    - bind :  새로운 함수를 생성하고, 주어진 this 값과 초기 인자들을 설정합니다.

함수 객체의 내부 슬롯

함수 객체의 내부 슬롯은 함수가 정의된 환경과 관련된 정보를 저장하는 내부 데이터 구조입니다. 내부 슬롯 중 하나인 [Environment] 는 가장 중요한 요소 중 하나 입니다. 함수 객체가 생성될때 함수가 정의된 어휘적 환경의 참조값을 [Environment]에 저장합니다. 함수가 정의된 어휘적 환경이라하면 바로 함수의 상위 스코프입니다. 함수 객체 생성 시점은 함수 선언문과 함수 표현식이 아래 처럼 살짝 다릅니다. 하지만 분명한 것 함수 객체 생성이 함수 호출보다 빠릅니다.

  • 함수 객체 생성 by 함수 선언문
    자바스크립트 엔진의 함수 코드를 평가할 때 식별자를 환경 레코드에 등록하고 함수 객체도 환경 레코드에 등록합니다.
  • 함수 객체 생성 by 함수 표현식
    함수 표현식으로 작성된 함수의 경우 자바스크립트 엔진이 평가 과정을 마치면 환경 레코드에 식별자만 등록됩니다. (평가 단계에서 var 타입 함수 표현식은 undefined 값도 저장되긴 합니다.) 즉 제대로된 값이 등록되지 않습니다. 이후 자바스크립트 엔진 실행 과정에서 선언 코드를 실행하여 환경 레코드에 함수 객체를 등록합니다.

중요한 점은 함수 객체가 생성될 때 함수가 선언된 위치, 즉 함수의 상위 스코프 참조 값을 저장한 다는 것입니다. 위에서 말했듯 분명히 함수 객체는 함수 호출 이전에 생성됩니다. 따라서 함수 객체 생성 당시 따로 호출 중인 함수가 없으므로 '현재 실행 컨텍스트의 어휘적 환경' 이 함수 객체의 [Environment] 에 저장되는것입니다.

이렇게 동작하는 이유는 바로 자바스크립트가 정적 스코프를 따르기 때문입니다. 함수는 어디에서 호출되는지 상관 없이 함수가 정의된 스코프 즉 상위 스코프를 반드시 기억해야합니다. 그렇기 때문에 함수는 자신의 내부 슬롯에 자신이 정의된 환경 즉 상위 스코프 참조를 저장해야합니다.

[Environment]의 사용

그렇다면 함수 객체의 내부 슬롯, [Environment]에 저장된 참조값은 언제 사용될 까요? 바로 이 함수 객체가 호출 될때 사용됩니다. 함수가 호출되면 자바스크립트 엔진은 함수를 평가합니다. 이때 함수 실행 컨텍스트가 생성됩니다. 함수 실행 컨텍스트가 생성되며 어휘적 환경도 생성됩니다. 이때 어휘적 환경의 외부 어휘적 환경 참조 값에 함수 객체의 [Environment]에 저장되어있던 참조값이 저장됩니다.

앞서서도 말했듯 [Environment]에는 함수가 선언된 위치 즉 함수 스코프의 참조 값이 저장됩니다. 따라서 이 함수가 실행될 때 내부에서 스코프 체이닝이 일어난다면 이 참조 값을 통해 외부 스코프, 함수가 선언된 스코프로 이동이 가능합니다.

정리하자면 이미 함수의 선언 위치(상위 스코프)를 가진 함수 객체가 존재하고 이 함수가 호출 될때 어휘적 환경이 생성되며 외부 어휘적 환경 참조값에 이 참조 값이 저장됩니다.

함수 객체 생성과 함수 실행 컨텍스트

함수 객체 생성이 먼저인지 함수 실행 컨텍스트 생성이 먼저인지 헷갈릴수 있습니다. 코드를 보면서 두 생성시기의 차이를 알아보겠습니다.

let x = 'global';

const fn = () => {
	const y='function';
	console.log(y);
};

fn();
  1. 코드가 실행됩니다.
  2. 자바스크립트 엔진이 전역 코드를 평가합니다.
  3. 식별자 x, 함수 식별자 fn이 환경 레코드에 저장됩니다. (정확히는 전역 어휘 환경의 선언적 환경 레코드에 저장, 이전글에 자세히 정리해 두었습니다.)
  4. 3번 과정에서 x의 값과 함수 fn의 값은 아직 환경 레코드에 등록되지 않았습니다.
  5. 전역 코드에서 자바스크립트 엔진 실행 단계가 진행됩니다.
  6. 변수 x의 값 'global'이 환경 레코드에 등록됩니다.
  7. 함수 fn의 선언 코드를 실행하며 함수 객체를 생성하고 환경 레코드에 저장합니다.
  8. 함수 fn이 호출됩니다.
  9. 자바스크립트 엔진이 함수 fn을 평가합니다.
  10. 함수 fn 실행 컨텍스트가 생성됩니다.
  11. ...

위 과정을 보면 7번 과정에서 함수 객체가 생성되었으며 10번 과정에서 함수 실행 컨텍스트가 생성되었습니다. 즉 함수 호출이 함수 선언 코드보다 나중에 실행되기 때문에 함수 객체 생성이 함수 실행 컨텍스트 생성보다 항사아 빠릅니다.

함수 선언문을 함수 선언 이전에 사용가능한 경우는 이미 자바스크립트 엔진 평가 단계에서 함수 객체가 환경 레코드에 등록되었기 때문에 함수 호출보다 함수 객체 생성이 빠릅니다.

var 타입 함수 표현식의 경우 평가 단계에서 unedefined로 초기화 되어 참조 자체는 되지만 실행은 함수 선언 코드 이후에 가능하므로 함수 객체 생성이 함수 실행 컨텍스트 생성보다 빠릅니다.

let, const 타입 함수 표현식은 위 에서 말했듯 함수 선언 코드 이후에 호출이 가능하므로 항상 함수 객체 생성이 함수 실행 컨텍스트 생성보다 빠릅니다.

그래서 어떻게 동작하는건데?

처음부터 다시 정리해보겠습니다.

파악 내용 1

우선 클로저는 중첩함수가 리턴되는 경우 외부 함수의 환경 레코드가 콜스택에서 사라져 중첩함수가 내부에서 외부함수 변수에 접근이 불가능해야 하지만 접근 가능한 상황을 말합니다.

뭔가 이상합니다. 이미 콜스택에서 사라져 버려서 참조가 불가능해야하고 오류가 발생해야 합니다. 그런데 변수가 여전히 참조 가능합니다. 이 이유를 알아보기 위해 함수 객체, 함수 객체 내부 슬롯을 알아보았습니다.

파악 내용 2

함수 객체가 생성될 때 함수 객체 내부 슬롯에 함수가 선언된 환경의 참조 값이 저장됩니다. 또 함수가 호출 될때 이 값이 외부 어휘적 환경 참조값으로 환경 레코드에 저장됩니다. 그 덕분에 외부 스코프로 이동이 필요한 스코프 체이닝이 가능합니다.

1차 정리

여기까지만 보면 중첩 함수에서 외부 함수의 변수에 접근 가능하다는 것만 설명 가능합니다. 왜 외부 함수가 종료되어 콜스택에서 빠져 나간 이후에도 중첩 함수에서 접근 가능한지는 설명이 되지 않습니다. 이게 왜 가능할까요??

외부 함수의 실행 컨텍스트가 콜스택에서 사라졌는데도 여전히 접근 가능한 이유는 바로 가비지 컬렉터의 특성에 있습니다.

가비지 컬렉터

가비지 컬렉터는 프로그래밍 언어의 메모리 관리를 자동화하는 프로세스입니다. 더 이상 사용되지 않는 부분, 즉 '가비지’를 주기적으로 찾아내어 메모리를 해제합니다. 즉 메모리 해제 대상은 바로 더이상 사용되지 않는 부분입니다.

자바스크립트에서 누군가 참조하고 있는 메모리를 더 이상 사용되지 않는 부분이라고 여기지 않습니다. 따라서 누군가 참조하고 있는 메모리 공간은 해제되지 않고 유지됩니다.

2차 정리

함수 객체는 항상 함수가 선언된 환경을 내부 슬롯에 저장합니다. 또 함수가 호출되면 해당 함수의 외부 어휘적 환경 참조에 해당 값이 복제됩니다. 자바스크립트는 정적 스코프를 따르기 때문에 이 참조값이 실행중 변화하지 않습니다. 즉 함수 객체의 참조값은 유지됩니다. 외부 함수가 종료된 경우에도 마찬가지로요.

위에서 가비지 컬렉션을 간단히 살펴보았습니다. 누군가 참조하고 있는 메모리 공간은 해제되지 않고 유지된다고합니다. 그렇습니다. 아무리 외부함수가 종료되어 콜스택에서 사라졌더라도 실행 중인 중첩함수가 외부 함수 스코프, 즉 외부 함수의 어휘적 환경을 참조하고 있다면 이 외부 함수의 어휘적 환경은 메모리에서 사라지지 않고 유지됩니다. 그렇기 때문에 클로저가 가능합니다. 어휘적 환경이 참조된 상태라 메모리에서 삭제되지 않고 존재하기 때문에요.

코드와 구조도로 과정을 이해해보겠습니다.

function a() {
  let x = 10;
  return function b() {
    return x = x + 1;
  }
}
const fn = a();
console.log(fn()); //11
  1. 함수 a 내부에서 함수 b가 선언되며 리턴됩니다.
  2. 함수 a가 실행되면 함수 a 실행 컨텍스트가 생성됩니다.
  3. 함수 b가 리턴되며 생성되었던 함수 a 실행 컨텍스트가 콜스택에서 제거됩니다.
  4. 함수 b가 리턴되며 실행됩니다.
  5. 함수 b 실행 컨텍스트가 생성됩니다. 이때 함수 b의 함수 객체에서 함수가 선언된 스코프의 참조값을 가져와 외부 어휘적 환경 참조 값에 복사합니다.
  6. 함수 b 내부에서 x가 호출됩니다.
  7. 함수 b 스코프 내부에 x가 없어 외부로 스코프를 이동합니다. 이때 함수 b 실행 컨텍스트에 저장된 외부 어휘적 환경 참조 값을 활용해 외부 스코프로 이동합니다.
    • 함수 b의 아우터(외부 어휘적 환경 참조)가 함수 a의 어휘적 환경을 참조하고 있기 때문에 메모리에서 함수 a의 어휘적 환경이 사라지지 않고 남아있게 됩니다. 덕분에 여전히 함수 b에서 함수 a의 어휘적 환경에 접근이 가능합니다.

사라진 함수 A 실행 컨텍스트

closure

함수 b가 실행중일때 구조입니다. 함수 b가 실행되어 함수 a 실행 컨텍스트가 콜스택에서 제거되었지만 메모리에선 제거되지 않고 여전히 존재합니다. 따라서 함수 b의 외부 어휘적 환경 참조를 통해 함수 a의 어휘적 환경에 접근 가능합니다.

1.3 클로저 특징

지금까지 클로저가 무엇인지와 왜 오류가 발생하지 않고 동작할 수 있는지를 살펴 보았습니다. 이제부터는 이 클로저의 장점과 단점을 살펴보며 어떤식으로 활용되는지 알아보겠습니다.

장점

클로저의 장점은 크게 3가지가 존재합니다.

  • 데이터 보존
  • 캡슐화(정보 접근 제한)
  • 모듈화 유리

데이터 보존

클로저의 정의 그 자체로 중첩 함수에서 중료된 외부 함수 스코프에 접근가능하다는 것이 클로저의 장점입니다. 접근 가능한 이 변수는 콜스택에 존재하지 않지만 참조되어 있어 메모리에서 사라지지 않습니다. 따라서 스코프 안에 가둔채 지속적으로 사용이 가능합니다.

function outerFn() {
  let x = 10;
  
  return function innerFn() {
    return x = x + 1;
  }
}

const fn = outerFn(); 
console.log(fn()); //11
console.log(fn()); //12
console.log(fn()); //13

innerFn 함수가 리턴,실행되며 콜스택에서 제거되는 outerFn의 어휘적 환경은 innerFn 함수의 어휘적 환경(외부 어휘적 환경 참조)이 참조하기 때문에 계속 메모리에 살아남아있게 됩니다. 따라서 fn() 출력 값이 처음엔 11, 다음엔 12, 마지마으로 13이 나오게 됩니다. outerFn의 변수 x가 메모리에 계속 살아있기 때문입니다.

캡슐화(정보 접근 제한)

자유변수로 직접적인 접근을 제한합니다. 변경이 되면 안되는 변수를 처리할 수 있고 무분별한 변수의 변화를 막을 수 있습니다. 따라서 보안에 용이합니다. 만약 자유 변수를 변경하고 싶다면 자유 변수를 변경하는 함수를 따로 만들어 처리할 수 있습니다(간접 접근).

자유변수

중첩 함수에서 접근 가능한 외부 함수의 변수를 자유 변수라 합니다. 이 자유변수는 메모리에 저장되어 지속적으로 사용이 가능합니다.

function outerFn() {
  let x = '자유변수';
  
  return function innerFn() {
    return x = x + '!';
  }
}
자유 변수 간접 접근

count 변수에 직접적으로 접근할 수 없지만 생성한 메소를 통해서 count 변수를 변경할 수 있습니다. 정해진 함수를 통해서만 변화를 줄 수 있기 때문에 예기치 못한 오류를 방지할 수 있습니다.

function createCounter(initialValue) {
  let count = initialValue;
  return {
    up: function() {
      return count+1;
    },
    down: function() {
        return count-1;
    }
  };
}

const counter = createCounter(10);
console.log(counter.up());  // 11
console.log(counter.up()); // 12
console.log(counter.down()); // 11

모듈화 유리

변수에 할당된 클로저 함수는 각자 독립적으로 값을 사용하고 보존됩니다. 아래의 코드를 보면 이해가 쉽습니다. counter1, counter2, counter3 변수가 선언되면 이 함수 내부 변수는 각자 독립적으로 보존됩니다. 따라서 counter1(10)으로 변수가 할당된 경우 초기 count 값이 10으로 시작되며 보존됩니다. counter1(10)으로 변수가 할당된 경우 count 값이 20으로 시작되며 보존됩니다. 덕분에 코드의 재사용성이 올라가고 관리하기 쉬운 구조로 작성할 수 있습니다.

function createCounter(initialValue) {
  let count = initialValue;
  return {
    up: function() {
      return count+1;
    },
    down: function() {
        return count-1;
    }
  };
}

const counter1 = createCounter(10);
const counter2 = createCounter(20);
const counter3 = createCounter(30);

console.log(counter1.up()); // 11
console.log(counter2.up()); // 21
console.log(counter3.up()); // 31

단점

클로저의 단점이라 하면 결국 콜스택에 존재하지 않은 어휘적 환경이 메모리에 계속 남아있다는 점 입니다. 변수가 메모리에 남아있어 외부 함수의 값을 활용할 수 있지만 너무 자주 사용되는 경우와 굳이 필요 없는데 메모리에 남기는 경우 등 메모리 사용량이 증가합니다. 이 불필요한 메모리 점유 증가는 프로그램의 퍼포먼스를 낮추기도 합니다. 따라서 불필요한 메모리 점유를 피하기 위해 클로저를 사용한 경우 개발자가 주의를 기울여야 합니다.

1.4 정리

클로저 간단 정리

  • 외부 함수, 중첩 함수가 존재해야한다.
  • 외부 함수가 중첩 함수를 리턴해야한다.
    - 중첩함수 실행되며 외부 함수 실행 컨텍스트 콜스택에서 제거된다.
  • 그럼에도 중첩함수에서 외부함수 어휘적 환경에 접근 가능하다.
  • 그러한 이유는 중첩 함수 외부 어휘적 환경 참조 값이 외부 함수 어휘적 환경을 참조하기 때문이다.
    - 가비지 콜렉터는 참조된 메모리는 지우지 않고 남겨둔다.
    - 덕분에 외부 함수 어휘적 환경이 메모리에 여전히 존재하게 된다.
  • 덕분에 외부 함수 변수는 일종의 숨겨진 변수로 활용 가능하다.
    - 직접 제어 X, 직접 설정한 함수로 제어가 가능하다.
  • 메모리를 계속 점유하기 때문에 주의가 필요하다.

클로저를 공부하려다보니 실행 컨텍스트, 호이스팅, 스코프 등등 정말 많은 공부가 필요했습니다. 검색으로 공부하다보면 서로 반대로 적혀있는 정보도 있고 간략화된 내용이라 이해가 안가는 부분도 존재했습니다. 많이 헷갈리던 와중에 딥다이브 책으로 공부하니 자바스크립트 엔진이 코드를 실행하는 과정을 순서대로 알려줘서 정말 많은 도움을 받았고 이해할 수 있었습니다. ㅎㅎ 딥다이브 정말 좋으니까 꼭 읽어보세요!!

2. 참고 자료

profile
프론트엔드 개발자

0개의 댓글