쉽게 말해 코드의 실행 환경이다.
var name = "jeongeun";
function wow(word){
console.log(word + ' ' + name);
}
function say(){
var name = "choi";
console.log(name);
wow('Hi');
}
say();
스크립트 실행시 나오는 결과는 choi, Hi jeongeun 이다. Lexical Scoping을 기억하면 쉽게 결과를 도출해낼 수 있다.
Lexical Scoping은 쉽게 말해 자신의 스코프와 가장 가까운 변수를 계속 참고하는 것이다.
Lexical Environment
변수, 함수와 같은 식별자, 외부 참조에 대한 정보가 저장된다.
렉시컬 환경은 두가지로 나눠지는데 Environment record와 outer 참조가 담겨져 있다. Environment record는 식별자에 대한 정보를 저장해두는 것이고 outer 참조는 외부 렉시컬 환경을 가리킨다.
Variable Environment
렉시컬 환경과 유사하지만 var
로 선언된 변수만 저장되는 점에서 다르다.
this 바인딩
this가 어떻게 바인딩 되는지를 나타낸다. (ES6부턴 렉시컬 환경의 Environment record 에서 this 바인딩을 나타낸다. 하지만 중요하지 않으니 알아두기만하자)
GEC일때 strict mode라면 undefined를 가리키고 아닐경우엔 전역 객체를 가리킨다. (브라우저: window, nodejs: global)
FEC일땐 함수가 어떻게 호출됐는지에 따라 달라진다.
두 가지 단계로 이루어진다.
생성 단계는 다시 렉시컬 환경, 변수 환경, this 바인딩 3단계로 나누어진다.
여기서 값은 변수에 매핑되지 않는다. var
는 undefined로 초기화가 되고 let
, const
는 아무 값도 가지지 않는다.
이제 실행이 되었을때 변수에 값이 할당 된다.
위의 코드에서 전역 컨텍스트를 객체 형식으로 표현하자면
'전역 컨텍스트' : {
변수객체: {
arguments : null,
variables : ['name', 'wow', 'say']
},
scopeChain: ['전역 컨텍스트'],
this: window
}
이제 위의 코드를 실행하게 되면 wow랑 say는 호이스팅 때문에 함수의 선언과 동시에 대입이 된다. 그 후 variables의 name에 값이 대입됩니다.
variables : [{name : 'jeongeun'}, {wow : Function}, {say : Function}]
say()를 호출하게 되면 새로운 함수 컨텍스트인 'say context'가 생성이 된다. 이를 객체 형식으로 나타낸다면
'say 컨텍스트': {
변수객체: {
arguments: null,
variables: ['name'] //초기화 후 [{name: 'choi'}]가 된다.
},
scopeChain : ["say 컨텍스트", "전역 컨텍스트"],
this: window
}
say함수의 name 변수는 say 컨텍스트 안에서 찾으면 된다. 그러면 console.log(name);
은 choi가 출력된다.
그 다음 wow('Hi');
가 호출되는데 say 컨텍스트 안에는 wow 변수가 존재하지 않는다. 따라서 스코프체인을 통하여 전역 컨텍스트에서 wow 변수가 존재하는지 찾아본다.