맨 처음 실행 컨텍스트가 콜스택에 쌓이고 생성 단계에 들어선다.
환경 레코드는 내부적으로 생성 단계와 실행 단계라는 두 가지 단계를 거쳐서 실행한다.
생성 단계에서 일어나는 일:
this
키워드 바인딩실행 단계에서 일어나는 일:
outer는 바깥 렉시컬 스코프 (record + outer)를 참조하는 객체입니다. 아우터를 통해 외부에 있는 식별자를 참조할 수 있습니다.
역할이 끝나면 콜스택에서 제거된다.
function a() {
let a = 0;
}
function b() {
let b = 0;
console.log(a);
}
a();
b();
결과:
[Function: a]
if (true) {
let x = 10;
console.log(x); // 10
}
console.log(x); // Error: x is not defined
함수 = null
을 넣어서 클로저를 풀어주어야 합니다.실제 구현 내용 일부를 외부에 감추어 은닉합니다.
function createCounter() {
let cnt = 1; // 외부 함수에만 존재하는 cnt
return function () { // 내부 함수에서 cnt를 사용하는 클로저
return cnt++;
};
}
const counter = createCounter();
console.log(counter()); // 1
// 외부에서 cnt에 접근하려고 하면:
console.log(cnt); // ReferenceError: cnt is not defined
createCounter
함수가 실행되어 cnt를 생성하고, 내부 함수를 반환합니다.createCounter
의 스코프에서만 유효한 변수지만, 내부 함수에서 이를 참조하고 있기 때문에 메모리에서 유지됩니다.파라미터에 따라 서로 다른 객체를 생성할 수 있습니다. 함수를 동적으로 생성할 수 있습니다.
function delayExecution(ms) {
return function (callback) {
setTimeout(callback, ms);
};
}
const delayedFunc = delayExecution(1000);
// 매개변수를 함수로 줌
delayedFunc(() => console.log("Executed after 1 second"));
delayExecution
함수가 실행되고 ms
매개변수로 1000
이 전달됩니다. delayExecution
함수는 내부 함수를 반환하며, 이 내부 함수는 callback
이라는 매개변수를 받습니다.delayedFunc
)에 콜백 함수로 () => console.log("Executed after 1 second")
가 전달됩니다.setTimeout
을 호출하며, callback
함수와 ms
값을 사용해 1초 후에 콜백 함수가 실행되도록 합니다.ms
변수에 접근할 수 있게 해주는 JavaScript의 특성 때문입니다. delayExecution
함수가 이미 실행되고 종료되었지만, 내부 함수는 ms
에 접근하고 있어 delayExecution
의 실행 컨텍스트가 메모리에서 사라지지 않고 유지됩니다.이로 인해 delayedFunc
내부에서는 언제든 ms
값을 참조할 수 있고, delayExecution
의 환경이 사라지지 않고 남아 있는 것이 클로저입니다.
함수의 결과를 캐싱하여 동일한 입력에 대해 반복 계산을 방지하는 방법으로, 클로저를 활용하여 이전 결과를 기억하도록 합니다.
function memoizeSquare() {
const cache = {}; // 이전 계산 결과를 저장하는 객체
return function (n) {
if (n in cache) {
console.log("Fetching from cache:", n);
return cache[n]; // 캐시에 결과가 있으면 반환
}
console.log("Calculating result for:", n);
const result = n * n;
cache[n] = result; // 새 계산 결과를 캐시에 저장
return result;
};
}
const square = memoizeSquare();
console.log(square(5)); // "Calculating result for: 5", 25
console.log(square(5)); // "Fetching from cache: 5", 25
console.log(square(7)); // "Calculating result for: 7", 49
console.log(square(7)); // "Fetching from cache: 7", 49
memoizeSquare
함수가 실행되고, 내부 함수 square
를 반환하며, cache
객체가 생성됩니다. 이 cache
객체는 이전 계산 결과를 저장하는 역할을 합니다.square
함수에 매개변수로 5
가 전달됩니다.cache
에 결과가 이미 있으면 해당 값을 반환하고, 없으면 새로 계산한 결과를 cache
에 저장한 후 반환합니다.memoizeSquare
함수는 실행된 후 종료되지만, square
함수가 cache
객체를 참조하고 있으므로, 메모리에서 삭제되지 않고 남아 있습니다. 이는 내부 함수가 외부 함수의 변수를 기억하는 클로저로 작동하기 때문입니다.
- 신기하게 클로저를 배우고, 오히려 실행 컨텍스트 작동 원리가 더 이해됨.
- 맨 처음 생성 과정에서 생긴 변수에 클로저에서 접근하는 것과 연관을 지으니 이해가 쉬움.
- 클로저를 사용할 일은 많지 않겠지만 실행 컨텍스트와 스코프를 공부하기엔 적격이다.