[javascript] 스코프
스코프
스코프(scope)는 변수와 상수, 매개변수가 언제 어디서 정의되는지 결정한다.
function f(x){
return x + "people";
}
f(3); // "3people"
x; // ReferenceError
위 코드에서 우리는 x의 스코프를 함수 f라고 말한다.
변수가 스코프 안에 있지 않다고 해서 변수가 존재하지 않는다는 것은 아니다. 가시성과 존재를 구분해야 한다. 가시성(visibility)이라고도 불리는 스코프는 프로그램의 현재 실행 중인 부분, 즉 실행 컨텍스트(execution context)에서 현재 보이고 접근할 수 있는 식별자들을 말한다. 존재한다는 말은 그 식별자가 메모리가 할당된(예약된) 무언가를 가리키고 있다는 뜻이다.
정적 스코프
자바스크립트의 스코프는 정적(lexical)이다. 정적 스코프는 어떤 변수가 함수 스코프 안에 있는지 함수를 정의할 때 알 수 있다는 뜻이다.
const x = 3;
function f(){
console.log(x);
console.log(y);
}
{ // 새 스코프
const y = 5;
f();
}
변수 x는 함수 f를 정의할 때 존재하지만, y는 그렇지 않다. 다른 새로운 스코프에서 y를 선언하고 그 스코프에서 f를 호출하더라도, f를 호출하면 x는 그 바디 안의 스코프에 있지만 y는 아니다. 함수 f는 자신의 정의될 때 접근할 수 있었던 식별자에는 여전히 접근할 수 있지만, 호출할 때 스코프에 있는 식별자에는 접근할 수 없다.
전역 스코프
프로그램을 시작할 때 암시적으로 주어지는 스코프를 전역 스코프라 한다. 전역 스코프에 선언된 것들을 전역 변수라고 하는데 이는 매우 안좋은 평가를 받고 있다. 전역 변수를 쓰면 마치 하늘이 무너지고 땅이 갈라질 것처럼 말하는데 왜일까? 전역 변수는 나쁜 것도 아니며 반드시 써야 하는 것이다. 전역 스코프에 몇 가지가 존재하는 건 피할 수 없다. 다만 피해야 하는 것은 전역 스코프를 남용하거나 이에 지나치게 의존하는 것이다.
블록 스코프
let과 const는 식별자를 블록 스코프에서 선언한다. 블록 스코프는 그 블록의 스코프에서만 보이는 식별자를 의미한다.
스코프 체인
현재 스코프에서 식별자를 검색할 때 상위 스코프를 연쇄적으로 찾아나가는 방식이다. 실행 컨텍스트(Execution context)가 생성될 때마다 LexcicalEnvironment가 만들어지고 그 안에 outer 참조 값이 있다. 이 값이 상위 스코프의 LexicalEnvironment를 가리키기 때문에 이를 통해 체인처럼 연결된다.
- 현재 실행 컨텍스트의 LexicalEnvironment의 Environment Record에서 식별자를 검색.
- 없으면 outer 참조 값으로 스코프 체인을 타고 올라가 상위 스코프의 EnvironmentRecord에서 식별자를 검색
- 이를 outer 참조 값이 null 일 때까지 계속하고 찾지 못한다면 에러 발생.