javascript-스코프
스코프
스코프 (유효범위)는 javascript를 포함한 모든 프로그래밍 언어의 기본적이고 중요한 개념이다.
1 | function add (x, y) { |
변수는 코드의 가장 바깥쪽에 함수 내부에 또는 코드블록에서 선언될 수 있다. 이렇게 선언된 변수는 변수가 선언된 위치에 따라서 스코프가 결정된다. 모든 식별자가 자신의 선언된 위치에서 스코프를 결정한다.
1 | var x = 'global'; |
위의 예제를 보면 동일한 이름을 가진 변수 x를 선언했고 함수내부, 외부에서 각각 참조를 한다. 이때 자바스크립트 엔진은 같은 두이름 중 어떤 것을 참조할지 결정한다. 이를 식별자 결정이라고 한다. 이때 엔진은 스코프를 규칙으로 삼아 참조할 변수를 결정한다. 즉 스코프는 식별자를 검색할 때 사용하는 규칙이라고도 할 수 있다.
코드의 문맥과 환경
코드가 어디서 실행되는지 주변에 어떤 코드가 있는지를 렉시컬 환경이라고 부른다.
스코프의 종류
코드는 전역과 지역으로 구분할 수 있다.
구분 | 설명 | 스코프 | 변수 |
---|---|---|---|
전역 | 코드의 가장 바깥 영역 | 전역 스코프 | 전역 변수 |
지역 | 함수의 몸체 내부 | 지역 스코프 | 지역 변수 |
- 전역과 지역 스코프전역이란 코드의 가장 바깥 부분을 말한다. 해당 스크립트에서 전역 변수는 1,2줄에서 선언된 x,y 변수이다. 이렇게 전역으로 선언된 전역 변수는 어디에서든 참조가 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24var x = 'global 1';
var y = 'global 2';
function outer () {
var z = 'inner 1';
console.log(x);
console.log(y);
console.log(z);
function inner () {
var x = 'inner 2';
console.log(x);
console.log(y);
console.log(z);
}
inner();
}
outer();
console.log(x);
console.log(y);
console.log(z);
따라서 outer()함수 inner()함수에서도 참조가 가능하여 해당 값이 출력된다.
outer함수내부에 선언된 z변수는 함수내부의 지역 변수이고 이 변수는 함수 몸체 내부에서만 참조가 가능하다. 코드의 마지막 줄에서 참조한 z라는 변수는 전역으로 선언되지 않았기 때문에 참조 에러가 난다.
inner함수또한 지역 변수로 x를 선언한다. inner함수에서 콘솔로 출력하는 x는 내부에 선언된 지역 변수 x를 출력하고 내부에 선언되진 않는 값들을 외부에서 찾아 출력한다.
이때 변수를 찾는 방식이 렉시컬 환경에 의해 내부 렉시컬 환경에서부터 전역 렉시컬 환경까지 확장되어 순차적으로 변수를 참조하게 된다.
스코프 체인
함수는 전역, 함수 몸체 내부에서 모두 선언이 가능하다. 함수는 중첩이 가능하므로 함수의 스코프 또한 중첩이 가능하다. 이는 스코프가 계층적 구조를 갖는다는 의미이다.
모든 스코프는 하나의 계층적 구조로 연결되며 최상위 스코프는 전역 스코프다. 이러한 구조를 스코프 체인이라 한다.
자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프부터 상위 스코프 방향으로 이동하여 변수를 검색한다.
스코프 체인에 의한 변수 검색
위에서 선언한 스크립트를 보면 전역 스코프로 선언한 변수를 지역 스코프에서 참조가 가능하지만 지역 스코프로 선언된 변수를 상위 스코프에서는 참조가 불가능하다.
계층적 구조를 갖는 스코프는 상위 스코프를 하위 스코프에서 참조하는 것은 가능하지만 하위 스코프에서 선언된 변수를 상위 스코프에서는 참조가 불가능 하다는 것을 의미한다.
스코프 체인에 의한 함수 검색
1 | // 전역 함수 |
bar함수에서 호출하는 foo함수는 전역으로 선언된 foo함수를 호출하는 것이 아닌 내부에 있는 foo함수를 먼저 호출하게 된다. 이는 변수와 마찬가지로 함수또한 식별자에 해당하기 때문에 스코프를 갖는다는 의미이다.
렉시컬 스코프
1 | var x = 1; |
위 스크립트의 상위스코프를 예측해보면 두가지 패턴이 예측된다.
- 함수를 호출한 곳에서 상위스코프를 결정
- 함수를 정의한 곳에서 상위 스코프를 결정
첫 번째 방식은 동적 스코프라고 부른다. 함수가 호출된 곳에서 상위 스코프를 결정한다면 bar함수가 호출된 foo함수가 bar함수의 상위 스코프가 될것이다.
두 번째 방식을 렉시컬 스코프, 정적 스코프라고 한다. 이는 함수가 정의되어 평가되는 시점에 스코프를 결정하는 방식이다.
대부분의 프로그래밍 언어는 렉시컬 스코프 방식을 따르고 있다.
따라서 해당 스크립트를 실행하면 전역 스코프로 선언된 변수의 값이 1이 두번 출력된다.
foo함수를 호출하면 젼역으로 선언한 함수인 bar함수를 호출하고 bar함수는 x라느 변수를 참조하기 위해 내부에서 검색한후 외부 스코프의 x를 참조하기 때문이다.
javascript-스코프