동일 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 콜 스택에 쌓아올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경, 순서를 보장한다.
** 동일 환경 : 전역 공간 / eval() / 함수 등
즉, 전역 컨텍스트를 실행하다가 함수 호출 부분을 만나면 그 함수를 순서대로 실행하는 방식이다.
함수 내에 함수가 있다면 마찬가지로 내부 함수를 먼저 수행하고 나머지 구문을 수행한다.
VariableEnvironment : 최초 실행 시의 스냅샷 / 실행 컨텍스트 생성 시 가장 먼저 정보가 담긴다.
LexicalEnvironment (사전적 환경): VariableEnvironment를 그대로 복사한다. 이후 코드 진행 중에는 Lexical~을 주로 활용하게 되며 서로 값이 달라진다.
위 두 환경 내에 environmentRecord, outerEnvrionmentReference가 담긴다.
environmentRecord : 현재 켄텍스트와 관련된 코드의 식별자 정보들이 순서대로 저장된다.
** 식별자 : 함수의 매개변수 식별자 / 선언한 함수가 있을 경우 그 자체 (전체) / var로 선언된 변수의 식별자
식별자 정보를 모두 수집한 이후에도 아직 실행 컨텍스트는 실행되지 않는다.
즉, 코드 실행 전에 자바스크립트 엔진은 해당 환경 코드 내의 변수명들을 모두 알고 있다.
https://f-lab.kr/insight/understanding-javascript-hoisting
위의 식별자 정보들이 모두 끌어올려지고, 변수의 경우 식별자만 끌어올려지고 할당부는 원래 자리에 남겨진다.
// 함수 선언문
function add(x,y){
let temp = x + y
return temp
}
add(1,2); // 함수명으로 함수 호출
// 익명 함수 표현식
var add2 = function () { /* ~~ */ }
add2();
// 기명 함수 표현식
var add3 = function add4() { /* ~~ */ }
add3(); // 실행
add4(); // Error
호이스팅 시 함수는 함수 전체를, 변수는 선언부만 끌어올린다.
즉, 함수 선언문의 경우 함수 전체가, 함수 표현식의 경우 변수의 선언부만 끌어올려진다.
변수의 할당부는 원래 자리에 남겨진다.
함수 선언문이 함수 호출부보다 아래에 있어도 정상 실행된다.
이럴 경우 같은 함수를 함수 선언문으로 두 번 이상 선언하면 마지막으로 선언한 함수의 로직으로 모든 함수가 수행된다.
스코프 : 식별자에 의한 유효 범위
자바스크립트에서는 특이하게 전역 공간 이외에는 함수에 의해서만 스코프가 생성된다.
스코프 체인 : 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것
outerEnvrionmentReference : 스코프 체인을 가능하게 하는 것
여러 스코프에서 동일한 식별자를 선언한 경우에는 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능
예를 들어, 전역 컨텍스트 / outer 컨텍스트 / outer 함수 내에 선언된 inner 컨텍스트가 있다.
전체 윤곽을 보면 전역 > outer > inner 으로 규모가 작아지지만, 스코프 체인을 타고 접근 가능한 변수의 수는 오히려 늘어난다.
전역 컨텍스트에서는 outer나 inner 스코프에서 생성된 변수에 접근할 수 없지만, inner 컨텍스트는 모든 스코프의 변수에 접근할 수 있다.
그러나 스코프 체인 상의 모든 변수에 접근 가능한 것은 아니다.
전역 공간과 inner 내에 같은 식별자 a가 선언되었다면, inner 내부에서는 스코프 체인 상에서 먼저 발견된 식별자인 inner의 a를 반환하게 된다.
즉, inner 함수 내에서 a를 선언했기 때문에 전역 변수의 a에는 접근할 수 없는데, 이를 변수 은닉화라고 한다.