스코프
- 스코프는 참조 대상 식별자를 찾아내기 위한 규칙이다.
- 스코프는 모든 프로그래밍 언어의 기본 개념으로 확실한 이해가 중요하다.
스코프의 존재 이유
변수를 프로그램에 추가하면 다음과 같은 재미있는 질문이 생긴다.
- 변수는 어디에 살아있는가? (어디에 저장되는가?)
- 필요할 때 프로그램은 어떻게 변수를 찾는가?
이 질문을 통해 알 수 있는 것은 특정 장소에 변수를 저장하고 나중에 그 변수를 찾는 데는 잘 정의된 규칙이 필요하다는 점이다. 바로 이런 규칙을 ‘스코프(Scope)’라 한다.
카일 심슨 , 『You Don’t Know JS: 타입과 문법, 스코프와 클로저』, 한빛미디어(2017), p193.
- 만약 스코프가 없었다면 다음과 같이 개발자의 워라밸은 하락했을 것이다.
스코프가 없다면 같은 식별자 이름은 충돌을 일으키므로 프로그램 전체에서 하나밖에 사용할 수 없다. 디렉터리가 없는 컴퓨터를 생각해보자. 디렉터리가 없다면 같은 이름을 갖는 파일을 하나밖에 만들 수 없다.
이웅모 , 『모던 자바스크립트 Deep Dive』, 위키북스(2020), 스코프
스코프의 구분
- 자바스크립트의 스코프는 다음과 같이 2가지로 나눌 수 있다.
- 전역 스코프(Global Scope)
- 지역 스코프(Local Scope)
전역 스코프
- 전역에서 선언된 변수는 전역 스코프를 갖는 전역 변수이다.
- 전역 변수는 코드 어디서든 참조가 가능하다.
지역 스코프
- 지역에서 선언된 변수는 지역 스코프를 갖는 지역 변수이다.
- 지역 변수는 그 지역과 그 지역의 하부 지역에서만 참조가 가능하다.
스코프의 작동 방식
- 프로그래밍 언어의 스코프의 작동 방식은 다음과 같이 2가지로 나뉜다.
- 렉시컬 스코프(Lexical Scope)
- 동적 스코프(Dynamic Scope)
렉시컬 스코프
- 대부분의 프로그래밍 언어가 사용하는 일반적인 방식이다.
- 렉싱 타임(Lexing Time)에 정의되는 스코프로, 함수를 어디서 선언하였는지에 따라 상위 스코프가 결정된다.
- 렉싱 타임에 대해 조금 더 자세히 알아보면 자바스크립트는 언어의 처리 과정인 컴파일레이션(Compilation)을 거치며, 이는 렉싱(Lexing), 파싱(Parsing), 코드 생성(Code-Generation)의 3단계로 나뉜다.
- 이 중 렉싱은 토크나이징(Tokenizing)이라고도 하며, 문자열을 나누어 의미 있는 조각으로 만드는 과정을 말한다.
- 정리하면 렉싱 타임에 정의된다는 뜻은 바로 컴파일레이션의 첫 단계인 렉싱 시점에 스코프가 확정된다는 뜻이다.
동적 스코프
- Bash Scripting이나 Perl의 일부 모드와 같은 소수의 언어에서 사용하는 방식이다.
- 함수를 어디서 호출하였는지에 따라 상위 스코프가 결정된다.
결론
- 자바스크립트는 렉시컬 스코프를 따른다.
- 따라서 함수의 호출 위치가 아닌 선언 위치에 따라 상위 스코프가 결정된다.
(참고) 렉시컬 스코프를 속이는 방법
- 다음 두 방법을 통해 렉시컬 스코프를 속일 수 있다. 그러나 이러한 방법은 엔진의 최적화 작업을 무효화 하여 결과적으로 성능을 하락시키기 때문에 사용이 금지된 사악한 방법들이다.
- eval()은 하나 이상의 변수 또는 함수 선언문을 포함하는 코드를 만나면 그 코드를 실행하면서 eval()이 호출된 위치에 있는 렉시컬 스코프를 런타임에 수정한다.
- with는 객체 참조를 하나의 스코프로, 속성을 확인자로 간주하여 런타임에 완전히 새로운 렉시컬 스코프를 생성한다. 그러나 with의 사용은 현재 완전히 금지되었다.
함수 / 블록 스코프
대부분의 C-family language는 블록 레벨 스코프(block-level scope)를 따른다. 블록 레벨 스코프란 코드 블록({…}) 내에서 유효한 스코프를 의미한다. 여기서 “유효하다”라는 것은 “참조(접근)할 수 있다”라는 뜻이다.
…하지만 자바스크립트는 함수 레벨 스코프(function-level scope)를 따른다. 함수 레벨 스코프란 함수 코드 블록 내에서 선언된 변수는 함수 코드 블록 내에서만 유효하고 함수 외부에서는 유효하지 않다(참조할 수 없다)는 것이다.
이웅모 , 『모던 자바스크립트 Deep Dive』, 위키북스(2020)
- 자바스크립트는 함수 레벨 스코프를 따르기 때문에 함수 내에서 선언된 매개변수와 변수는 함수 외부에서는 유효하지 않다.
- 그러나 자바스크립트에서도 블록 레벨 스코프를 구현할 수 있는 방법이 있다. 바로 ECMAScript 6에서 도입된 let, const keyword를 사용하는 방법이다.
전역변수 문제
- 그렇다면 함수 밖에서 선언된 변수는 어떨까? 자바스크립트는 블록 레벨 스코프를 사용하지 않으므로 함수 밖에서 선언된 변수는 모두 전역 스코프를 갖게된다.
- 바로 이러한 문제 때문에 자바스크립트는 전역 변수의 남발을 주의해야 한다. 전역 변수의 이름이 중복되면 의도치 않은 재할당이 발생해 코드 예측을 어렵게 만드므로 사용을 자제해야 한다.
전역변수를 줄이는 방법
References
카일 심슨 , 『You Don’t Know JS: 타입과 문법, 스코프와 클로저』, 한빛미디어(2017)
이웅모 , 『모던 자바스크립트 Deep Dive』, 위키북스(2020)
MDN