Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

24-1장 클로저 - 한수지 #992

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions docs/24_클로저/한수지.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
## 24장. ✨ 클로저

> MDN의 클로저 정의: **클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.**

자바스크립트는 `렉시컬 스코프를 따르는 프로그래밍 언어`이다.

### 📌 24-1. 렉시컬 스코프

> **렉시컬 스코프**(정적 스코프)란, 자바스크립트 엔진이 함수를 어디서 호출했는지가 아니라 **함수를 어디에서 정의했는지에 따라 상위 스코프를 결정하는 것**을 말한다.

간단하게 말해, `렉시컬 스코프는 함수 정의 위치에 따라 상위 스코프를 결정`한다.

```js
const x = 1;

function foo() {
const x = 10;
bar();
}

function bar() {
console.log(x);
}

foo(); // 1
bar(); // 1
```

위 예제에서 foo, bar 함수는 모두 전역에서 정의된 함수이다.

앞서, 자바스크립트 엔진은 함수를 어디에서 정의했는지에 따라 상위 스코프를 결정한다고 말하였는데 foo, bar 함수의 상위 스코프는 바로 전역이다.

> 상위 스코프를 결정한다는 말은 **렉시컬 환경의 '외부 렉시컬 환경에 대한 참조'에 저장할 참조값을 결정한다는 말**과 같다.

정리하자면, `상위 스코프에 대한 참조`는 `함수 정의가 평가되는 시점`에 `함수가 정의된 환경(위치)에 의해 결정`된다.

이것이 바로 `렉시컬 스코프`이다.

---

### 📌 24-2. 함수 객체의 내부 슬롯 `[[Environment]]`

함수가 정의된 환경(위치)과 호출되는 환경(위치)는 다를 수 있다.

렉시컬 스코프가 가능하려면 **함수는 자신이 호출되는 환경과는 상관없이 자신이 정의된 환경, 즉 상위 스코프(= 함수 정의가 위치하는 스코프가 바로 상위 스코프)를 기억**해야 한다.

> 함수는 **자신의 내부 슬롯** `[[Environment]]`에 자신이 정의된 환경, 즉 **상위 스코프의 참조를 저장**한다.

이때 `[[Environment]]`에 저장된 상위 스코프의 참조는 `현재 실행 중인 실행 컨텍스트의 렉시컬 환경`을 가리킨다.

외부 렉시컬 환경에 대한 참조는 함수 객체의 내부 슬롯 `[[Environment]]`에 저장된 렉시컬 환경의 참조가 할당된다.

---

### 📌 24-3. 클로저와 렉시컬 환경

> MDN의 클로저 정의: **클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.**

클로저 정의를 바탕으로 아래의 예시코드를 살펴보자.

```js
const x = 1;

function outer() {
const x = 10;

const inner = function () {
console.log(x); // 10
};

return inner;
}

// outer 함수를 호출하면 중첩함수 inner를 반환한다.
// outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 팝되어 제거된다.
const innerFunc = outer();
innerFunc();
```

> **외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명 주기가 종료한 외부 변수를 참조**할 수 있다. 이러한 중첩 함수를 **클로저** 라고 부른다.

자바스크립트의 모든 함수는 상위 스코프를 기억하므로 이론적으론 모든 함수는 클로저이다.

하지만, **일반적으로 모든 함수를 클로저라고 하지 않는다.**

`상위 스코프의 어떤 식별자도 참조하지 않는 경우` 대부분의 모던 `브라우저는 최적화를 통해 상위 스코프를 기억하지 않는다.` (참조하지도 않는 식별자를 기억하는 일은 메모리 낭비이기 때문)

따라서, 클로저는 조건이 붙는다.

1. 중첩 함수가 상위 스코프의 식별자를 참조하고 있다.
2. 중첩 함수가 외부 함수보다 더 오래 유지되는 경우에 한정된다.
Loading