스코프는 자바스크립트 뿐만 아니라 모든 프로그래밍 언어의 기본적인 주요 개념중 하나입니다.
이러한 스코프의 개념을 간단히 정의한다면, '변수나 함수의 유효 범위'를 의미하며, 이러한 개념을 변수에 적용해 본다면 대표적으로 전역 변수(Local Variables)와 지역 변수(Global Variables)이 두가지로 요약이 가능합니다.
① 전역 변수와 지역 변수를 활용한 스코프의 이해) 자바스크립트 엔진은 어떤 변수를 참조할 것인지를 정적 스코프(소스 코드가 정의 될 때 변수의 스코프 범위가 결정되는 방식)에 입각하여 결정하는데, 이를 '식별자 결정'이라고 하며 스코프는 이때 중요한 역할을 합니다.
자바스크립트 엔진은 식별자 결정 우선 범위를 해당 명령문이 실행 되는 지역에 스코프를 우선적으로 두고, 해당 스코프에 찾고자 하는 식별자가 존재하지 않을시 상위에서, 그 다음 상위에서, 그것도 없다면 전역에서 선언된 변수를 검색하게 됩니다. 이러한 개념을 스코프 체인(scope chain) 이라고 부릅니다.
let x = 'gloabal' // 전역 변수로 선언 된 x는 어디서든, 어느 스코프든 참조될 수 있는 변수를 의미하며 이는 모든 코드가 전역 변수를 참조하고 변경할 수 있는 암묵적 결합(implicit coupling)을 허용한 것을 의미합니다. function field(){ let x = 'local' // 새로운 x 변수에 local 문자열을 선언 및 초기화 하면 console.log(x); // field 함수에서 호출한 x는 'local' 문자열을 담고 있는 x가 호출 됩니다. 즉 이때 선언된 x는 'local' 문자열을 담고 있는 변수를 의미하며, 해당 지역 스코프와 하위 지역 스코프에서만 유효합니다. } field(); // 만약 함수를 호출하게 되면 field 함수의 코드 블록을 순차적으로 실행하게 되는데 console.log(x); // 그 후에 field 함수의 지역 스코프 및 하위 스코프를 제외한 상위 스코프(전역 스코프를 포함) 지역에서 x를 호출한다면 이때는 field 함수의 x가 아니라 전역 지역의 변수 x를 호출하여 x의 값인'gloabal'을 출력하게 됩니다.
★ 특히 자바스크립트에서 함수의 스코프를 구분 짓는 스코프는 정적 스코프(static scope), 다른 말로 렉시컬 스코프(lexical scope)라고 하는데, 이는 함수가 정의된 시점에서 상위 스코프가 정적으로 결정되는 방식을 의미합니다.
즉 함수를 어디서 호출했는지에 중점을 둔 동적 스코프 빙식으로 해당 함수의 스코프를 결정짓는 방식이 아니라 함수가 어디에서 정의 되었는지에 중점을 둔 정적 스코프 방식을 취한다는 것이죠.
예를 들어 위의 예제에서 함수 field는 전역 지역에서 정의되었으므로 상위 스코프는 전역 지역이 되며, 중첩 함수의 경우 하위 함수의 상위 스코프는 하위 함수를 감싸고 있는 한 단계 위의 상위 함수의 스코프로 결정됩니다.
참고로 함수의 상위 스코프는 언제나 자신이 정의된 스코프가 됩니다.
function outerFunction() { // 외부 함수의 스코프이자 innerFunction의 상위 스코프 let outerVariable = 'I am outer'; function innerFunction() { // 내부 함수의 스코프 let innerVariable = 'I am inner'; console.log(innerVariable); // 내부 함수에 선언되었으므로 당연히 내부 함수에서 해당 변수를 사용하는 것이 가능하지만 console.log(outerVariable); // 외부 함수인 outerVariable 또한 스코프 체인 검색시 외부 스코프( 현재 innerFunction의 상위 스코프는 outerFunction) 에 해당 변수의 검색이 가능합니다. } innerFunction(); // 내부 함수 호출 } outerFunction(); // 아래 라인에서 innerVariable에 접근을 시도할 경우 해당 변수는 let 키워드(블록 레벨 스코프) 로 선언되었기 때문에 해당 스코프를 벗어난 지역에서의 검색이 불가능합니다. // console.log(innerVariable); // 에러: innerVariable is not defined