함수가 호출되면 JS엔진은 실행 컨텍스트를 생성한다.
function printName() {
return 'HAHA NANA'
}
function findName() {
return printName()
}
function sayName() {
return findName()
}
sayName()
JS엔진은 JS파일을 읽기 시작하면서 먼저 글로벌 실행 컨텍스트를 만든다. 콜스택에는 실행 컨텍스트가 하나씩 push된다. printName함수까지 호출이 완료되었을 때 콜스택은 다음과 같다.
printName()
findName()
sayMyName()
global()
실행 컨텍스트가 하나씩 pop off되고 마지막에 전역 실행 컨텍스트가 남는다. 마지막 코드까지 실행이 완료되면 전역 실행 컨텍스트도 스택에서 pop off된다.
자바스크립트 코드는 전역 실행 컨텍스트나 호출된 함수의 실행 컨텍스트 안에서 코드가 실행된다.
자세히 뜯어보면,
JS 엔진이 가장 먼저 하는 일은 전역 실행 컨텍스트를 만든다.
전역 실행 컨텍스트는 코드 내부 별도의 실헹 명령 없이 브라우저나 node에서 자동으로 실행된다.
실행 컨텍스트는 전역 객체, this를 만든다. 이때 전역 객체와 this는 동일하다. node에서 전역 객체는 global이고 브라우저에서는 window이다.
var a = 'a'
변수를 전역 객체에 추가할 수 있는데 위와 같이 전역에서 선언한 변수는 전역 객체에 key와 value로 저장된다.
함수가 호출되고 JS엔진이 creation phase(생성 단계)를 완료하면 execution phase(실행 단계)에서 코드를 수행한다.
Lexical environment and function scope
실행 컨텍스트는 stack frame이다. 즉 함수가 실행되면 콜스택에 push되어 콜스택에 의해 관리된다. 실행 컨텍스트로 어떤 렉시컬 환경이 실행되고 있는지 알 수 있다.
반면 렉시컬 환경은 스코프 그자체이다. 렉시컬 환경은 실행 컨텍스트가 소스 코드를 실행하기 위해 필요한 것들을 관리한다. 예를 들면 식별자(variables/funcitons)와 식별자에 바인딩된 값, 그리고 상위 스코프(상위 렉시컬 환경)에 대한 참조를 기록한다.
모든 실행 컨텍스트는 상응하는 렉시컬 환경이 있다.
만약 어떤 함수에 내부 함수가 있으면 함수 객체의 숨김 프로퍼티인 ( [[Environment]] )에 렉시컬 환경에 대한 참조를 저장한다
그래서 모든 함수는 실행컨텍스트와 연관된 렉시컬 환경을 추적할 수 있다.
모든 렉시컬 환경은 부모 렉시컬 환경을 추적할 수 있다. 그 결과 체인이 만들어진다.
function printName() {
return 'HAHA NANA'
}
function findName() {
function a (){
//declared inside of here
//this function is lexically inside the findName
}
return printName()
}
function sayName() {
return findName()
}
window.sayName()