자바스크립트에서 스코프(scope)란 무엇일까?
스코프는 쉽게 말해 유효 범위를 뜻하는 단어이다.
자바스크립트뿐만 아니라 프로그래밍 언어에서 중요한 개념이다.
먼저 자바스크립트에서 변수를 선언하는 키워드는 3가지가 있다.
- var
- let
- const
var로 선언한 변수와 let, const키워드로 선언한 변수의 스코프도 서로 다르게 동작한다.
간단하게 함수로 예시를 들어본다면 아래와 같다.
function add(a, b) {
console.log(a, b) // 1, 10
return a + b
}
add(1, 10); //Executed JavaScript Failed:
console.log(a, b) // a is not defined
즉, 위 코드를 살펴보면 매개변수는 함수 내부에서만 참조할 수 있다.
-> 이는 매개변수의 스코프는 함수 내부이다.
var a = 1 // 코드의 가장 외부 영역에서 선언
if(true) {
var b = 2 // 코드 블럭 내부 선언 변수
if(true) {
var c = 3 // 중첩된 코드 블럭 내부 선언 변수
}
}
function foo() {
var d = 4 // 함수 내 선언 변수
function bar() {
var e = 5 // 중첩 함수 내 선언 변수
}
}
console.log(a) // 1
console.log(b) // 2
console.log(c) // 3
console.log(d) // d is not defined
console.log(e) // e is not defined
변수는 선언된 위치에 따라 스코프가 결정된다.
-> 즉, 다른 코드가 해당 변수를 참조할 수 있는 범위가 결정되는 것이다.
위와 같이 다른 코드가 식별자 본인을 참조할 수 있는 유효 범위를 스코프 라고 칭한다.
변수 'd'와 'e'는 해당 변수가 선언된 함수 내부에서만 접근 가능하기에 함수 foo(), bar() 내부에서 호출해야 한다.
예를 들어 아래와 같이 수정한다면 4와 5가 출력된다.
function foo() {
var d = 4 // 함수 내 선언 변수
function bar() {
var e = 5 // 중첩 함수 내 선언 변수
console.log(e) // 5
}
bar()
console.log(d) // 4
}
foo()
스코프의 종류
스코프의 종류는 아래와 같다.
구분 | 설명 | 스코프 | 변수 |
전역 | 코드의 가장 바깥 영역 | 전역 스코프 | 전역 변수 |
지역 | 함수 몸체 내부 | 지역 스코프 | 지역 변수 |
- 전역 변수는 어디서든지 참조할 수 있다.
- 지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효하다.
스코프 체인
함수 몸체 내부에서 정의한 함수를 중첩 함수라고 부르며, 중첩 함수를 포함하는 함수를 외부 함수라고 부른다.
함수는 중첩될 수 있으니 함수의 지역 스코프 또한 중첩될 수 있다!
-> 스코프가 함수의 중첩에 의해 계층적 구조를 갖는다.
변수를 참조할 때 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
그러나, 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조할 수 있지만 하위 스코프에서 유효한 변수를 상위 스코프에서 참조할 수는 없다!!
렉시컬 스코프
var x = 1
function foo() {
var x = 10
bar()
}
function bar() {
console.log(x)
}
foo() // 1
bar() // 1
위 결과가 어떻게 될지 생각해 보면 아래 두 패턴을 생각해 볼 수 있다.
- 함수를 어디서 호출했는지에 따라 함수의 상위 스코프를 결정한다.
- 함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정한다.
만약, 첫 번째 패턴이라면 bar 함수의 상위 스코프는 foo 함수의 지역 스코프와 전역 스코프이다.
두 번째 패턴이라면 bar 함수의 상위 스코프는 전역 스코프일 것이다.
첫 번째 패턴을 동적 스코프
두 번째 패턴을 정적 스코프(렉시컬 스코프)라고 한다.
자바스크립트는 렉시컬 스코프이므로 두 번째 패턴이다!
따라서 출력 결과물은 1과 1이 될 것이다.