스코프 (Scope)
스코프란 식별자가 유효한 범위이다. 모든 식별자는 "자신이 선언된 위치"에 의해 다른 코드가 식별자를 참조할 수 있는 유효 범위가 결정되는데 이것이 바로 스코프인 것이다.
스코프 개념이 없으면 같은 이름을 가지는 변수를 사용할 수 없게 된다. 그 이유는 같은 이름을 갖는 변수는 충돌을 일으키기 떄문이다. 스코프라는 유효 범위를 통하여 식별자인 변수 이름의 충돌을 방지할 수 있다. 스코프 내에서는 식별자가 유일해야 하지만, 다른 스코프에서는 같은 이름의 식별자를 사용할 수 있다. 스코프는 "네임스페이스"이다.
스코프의 종류
코드는 전역(Global, 코드의 가장 바깥 영역)과 지역(Local, 함수 몸체 내부)으로 구분되는데, 변수는 자신이 선언된 위치에 의해 자신이 유효한 범위인 스코프가 결정된다. 이로 인해 전역 변수, 지역 변수라는 개념이 나오는 것이다.
- 전역 스코프: 전역은 코드의 가장 바깥 영역을 말하며, 전역에서 선언된 변수는 어디서든지 참조 가능하다.
- 지역 스코프: 지역은 함수 몸체 내부를 말하며, 지역에서 선언된 변수는 자신이 선언된 지역과 하위 지역에서만 참조 가능하다.
스코프 체인
함수 내부에 정의한 함수를 중첩 함수라 한다. 함수가 중첩되듯이 함수의 지역 스코프 또한 중첩될 수 있다. 이는 스코프가 함수의 중첩에 의해 계층적인 구조를 가진다는 것을 보여준다. 중첩 함수의 외부 함수의 스코프는 중첩 함수의 상위 스코프이다.
모든 스코프는 하나의 계층적 구조로 연결되며, 모든 지역 스코프의 최상위 스코프는 전역 스코프가 된다. 이러한 계층적 구조를 "스코프 체인(Scope Chain)이라고 한다.
변수를 참조할 때, 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프(하위 스코프)에서 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다. 이러한 원리를 기반으로 상위 스코프에서 선언한 변수를 하위 스코프에서 참조할 수 있는 것이다.
그런데, 반대로 하위 스코프에서 유효한 변수는 상위 스코프에서 참조할 수 없다. 이는 자바스크립트 엔진이 하위 스코프로 내려가며 식별자를 검색하지 않기 때문이다.
함수 레벨 스코프
대부분의 프로그래밍 언어는 함수 몸체만이 아닌 모든 "코드 블록"이 지역 스코프를 생성한다. 이를 "블록 레벨 스코프(Block Level Scope)"라고 한다. 그런데 자바스크립트의 var 키워드로 선언된 변수는 오직 "함수의 코드 블록"만을 지역 스코프로 인정한다. 이를 "함수 레벨 스코프(Function Level Scope)"라고 한다.
함수 밖에서 var 키워드로 선언된 변수는 코드 블록 내에서 선언되어도 모두 전역 변수가 된다. 그렇기에 전역 변수가 중복될 가능성도 생기고 변수의 값이 재할당될 수 있다.
ES6에 도입된 let, const 키워드는 모두 블록 레벨 스코프를 지원한다.
렉시컬 스코프
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x)
}
foo(); // ?
bar(); // ?
프로그래밍 언어는 일반적으로 "함수를 어디에서 호출했는가", "함수를 어디에서 정의했는가"에 따라 함수의 상위 스코프를 결정한다.
함수의 호출 시점에 동적으로 상위 스코프를 결정하는 첫 번째 방식을 "동적 스코프"라고 한다.
함수 정의가 평가되는 시점에 정적으로 상위 스코프가 결정되는 두 번쨰 방식을 "렉시컬 스코프(정적 스코프)"라고 한다.
대다수의 프로그래밍 언어는 렉스컬 스코프를 따르며, 자바스크립트 또한 렉시컬 스코프를 따른다. 렉시컬 스코프에서는 함수가 호출된 위치는 상위 스코프 결정에 어떠한 영향도 주지 않으며, 함수의 상위 스코프는 언제나 자신이 정의된 스코프가 된다.
래퍼런스(Reference)
https://www.yes24.com/Product/Goods/92742567