
javascript는 코드를 한줄 한줄 읽어가며 실행한다.
컴파일 언어가 아니라 스크립트 언어이기 때문이다.
한줄 한줄 읽을 때 마다 그 상태를 저장하는데 context라고도 표현한다.
현재 코드가 실행되는 상황을 의미한다.

함수 실행 컨텍스트, 글로벌 실행 컨텍스트가 있다.
우리가 흔히 아는 {} 브레이스 마다 컨텍스트가 만들어진다고 생각하면 쉽다.
이 컨텍스트에는 this, arguments, 선언된 변수, 선언된 함수, 제어 흐름의 위치 들이 저장되어 있다.
보통 this를 컨텍스트라고 많이 말하는데, 맞는 말이긴 한데 정확히 말하면 위의 요소들이 모두 포함되어 있는 것이다.

컨텍스트는 콜 스택으로 구성되어서 호출된다.
위의 코드를 예시로 들어보자.
var c = 5 변수를 글로벌 컨텍스트 pushmultiply() 함수 호출로 인해 함수 컨텍스트 pushrandom() 함수 호출로 인해 함수 컨텍스트 pushreturn 10 으로 함수를 벗어나 함수 컨텍스트 popreturn c * random() 으로 함수를 벗어나 함수 컨텍스트 popmultiply()함수 종료로 마지막 코드가 끝났으므로, 글로벌 컨텍스트 pop렉시컬 환경은 실행 컨텍스트 의 자식 집합의 개념으로, 2가지로 이루어져 있다.

컨텍스트와 거의 유사한 계층 구조로 이루어진다.
왜냐면 컨텍스트 내부에 렉시컬 환경이 있는 포함집합의 개념이기 때문이다.
글로벌 렉시컬 환경에서는 outerFunction() 객체가 있으므로, 환경레코드는 저렇게 된다.
그리고 글로벌 렉시컬 환경은 최상위 컨텍스트에 존재하기 때문에, 외부렉시컬 환경 또한 없다.
outerFunction 렉시컬 환경, innerFunction 렉시컬 환경 또한 같은 언리로 뿅뿅 하고 만들어진다!
내가 아는건 클로저스 밖에 모르는데
클로저란 렉시컬 환경을 응용해서, 해당 렉시컬 환경이 사라졌음에도 이를 기억하고 사용하는 것을 의미한다.
말이 너무 어려운가? 예시로 설명해보겠다.

글로벌 스코프 기준으로 살펴보자.
const newFunction = outerFunction('outside');
첫 번째 줄로 인해 outerFunction 렉시컬 환경이 만들어진다.
이때, arugments로 'outisde'가 들어간다.
newFunction('inside');
두 번째 줄에서 innerFunction 렉시컬 환경이 만들어진다.
이 때, arguments로 'inside'가 전달된다.
그런데 innerFunction 렉시컬 환경은 outerFunction() 를 외부렉시컬 환경을 가지는 것이 아니라, outerFunction('outside') 로 가지는 것임을 알아야 한다.
두 개의 의미는 다르다.
이를 통해 글로벌 렉시컬환경에서도 innerFucntion 렉시컬 환경으로 바로 접근할 수 있다.
클로저를 통해 데이터를 은닉화할 수 있다.
function createCounter() {
// 은닉화된 변수
let count = 0;
// 클로저를 사용하여 count 변수에 접근하는 함수들
return {
increment: function() {
count++;
console.log(count);
},
decrement: function() {
count--;
console.log(count);
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
console.log(counter.getCount()); // 1
외부에서는 count 변수에 접근할 수 없지만, 마치 클래스처럼 이를 사용할 수 있다.
이것이 바로 클로저를 사용하는 이유이다.