자바스크립트의 스코프는 함수의 중첩에 따라 스코프가 계층적으로 연결된다. 이러한 구조를 스코프 체인
이라고 한다. 모든 지역 스코프의 최상위 스코프는 전역 스코프가 된다.
자바스크립트 엔진은 변수를 참조할 때 스코프 체인을 통하여 상위 스코프로 이동하면서 변수를 검색한다. 이때 실행 컨텍스트(Execution Context)
스택과 렉시컬 환경(Lexical Environment)
을 실제로 생성한다. 전자는 코드의 실행 순서를 관리하고, 후자는 스코프와 식별자를 관리한다. 렉시컬 환경
은 선언된 변수 식별자를 키(key)로 등록하고, 변수 할당이 일어나면 해당하는 키의 값을 변경한다.
검색의 방향이 하위에서 상위로 이동하므로, 상위 스코프의 유효한 변수를 하위 스코프에서 마음껏 참조할 수 있지만, 그 반대는 성립하지 않는다.
let x = "global x",
y = "global y";
function outer() {
let z = "outer's local z";
function inner() {
let x = "inner's local x";
console.log(x); // inner's local x
console.log(y); // global y
console.log(z); // outer's local z
}
inner();
}
outer();
console.log(z); // ReferenceError: z is not defined
스코프는 다음과 같이 참조할 변수를 검색한다.
x
를 참조하기 위해 먼저 inner
함수 스코프를 검색한다. 해당 변수가 존재하므로 검색을 종료한다.y
를 참조하기 위해 inner
함수 스코프를 검색한다. 선언된 y
가 없으므로 상위 스코프인 outer
함수 스코프를 검색한다. outer
에도 선언된 y
가 없으므로 상위 스코프인 전역 스코프를 검색한다. 여기서 찾은 y
를 참조하고 검색을 종료한다.z
를 참조하기 위해 inner
함수 스코프를 검색한다. 선언된 z
가 없으므로 상위 스코프인 outer
함수 스코프를 검색한다. 선언된 z
가 있으므로 z
를 참조하고 검색을 종료한다.z
는 최상위 스코프인 전역 스코프 어디에도 없으므로 참조 에러가 발생한다. 즉, 하위 스코프로는 검색하지 않는다.function foo() {
console.log("global function foo");
}
function bar() {
function foo() {
console.log("local function foo");
}
foo(); // local function foo
}
bar();
함수 선언문으로 함수를 정의하면 런타임 이전에 함수 객체가 생성되고, 같은 이름의 식별자에 할당된다. 따라서 bar
함수 내부의 foo
를 호출하면 같은 이름의 식별자 foo
를 검색한다.
참고
『초보자를 위한 자바스크립트 200제』, 고재도, 노지연, 정보 문화사, p.125~127
『모던 자바스크립트 Deep Dive』, 이웅모, 위키북스, p.194~197, p.364~367