JAVASCRIPT 스코프(Scope) - 3. 렉시컬 스코프
스코프(scope)란?
▶ 스코프(scope)는 변수나 함수가 유효한 범위를 의미합니다.
즉, 스코프는 코드의 어떤 부분에서 변수를 참조할 수 있는지를 결정하는 것으로
오늘은 자바스크립트에 있는 스코프 유형에 대해 알아보겠습니다.
3. 렉시컬 스코프(Lexical Scope)
▶ 렉시컬 스코프(Lexical Scope)는 함수가 선언된 위치에 따라 변수의 스코프가 결정되는 스코프로, 다른 말로는 정적 스코프(Static Scope)라고도 합니다.
자바스크립트는 코드를 실행할 때가 아니라 함수를 선언할 때 변수의 스코프를 결정합니다. 때문에 함수가 어디에 선언되었는지에 따라 그 함수가 어떤 변수에 접근할 수 있는지 결정하고, 중첩된 함수일 경우에는 내부 함수가 외부 함수의 변수에 접근할 수 있는지를 결정하는데 렉시컬 스코프는 코드의 구조를 그대로 반영합니다.
즉, 함수를 어디에서 호출했는지가 스코프에 영향을 주지 않고 함수를 선언한 위치가 영향을 줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var outsideVar = "I'm outside!";
function outerFunction() {
var insideVar = "I'm inside!";
function innerFunction() {
console.log(insideVar); // "I'm inside!"
console.log(outsideVar); // "I'm outside!"
}
innerFunction();
}
outerFunction();
- 위 예시에서 innerFunction은 외부 함수인 outerFunction 내부에 정의되어 있습니다.
따라서 innerFunction은 외부 함수인 outerFunction의 변수인 insideVar와 전역 스코프의 변수인 outsideVar에 접근할 수 있습니다. 이는 렉시컬 스코프에 따라 함수가 선언된 위치에 따라 변수의 스코프가 결정됨을 보여줍니다.
렉시컬 스코프(Lexical Scope)의 특징
1. 정적 스코프 결정
: 렉시컬 스코프는 함수를 선언할 때의 위치에 따라 변수의 스코프가 결정되는데 이는 코드의 구조를 기반으로 스코프가 정적으로 결정되는 것을 의미하며, 함수가 호출된 위치는 스코프에 영향을 주지 않습니다.
2. 중첩 함수의 스코프 체인
: 중첩된 함수의 경우 내부 함수는 외부 함수의 변수에 접근할 수 있고, 중첩 함수의 스코프 체인은 렉시컬 스코프에 따라 결정됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function outerFunction() {
var outerVar = "I'm an outer variable";
function innerFunction() {
var innerVar = "I'm an inner variable";
console.log(outerVar); // "I'm an outer variable"
console.log(innerVar); // "I'm an inner variable"
}
innerFunction();
console.log(outerVar); // "I'm an outer variable"
console.log(innerVar); // ReferenceError: innerVar is not defined
}
outerFunction();
console.log(outerVar); // ReferenceError: outerVar is not defined
렉시컬 스코프의 장점과 단점
장점
1. 예측 가능한 스코프
: 렉시컬 스코프는 변수의 스코프가 코드를 작성할 때의 위치에 의해 결정되므로 코드를 예측하여 읽고 이해하기 쉽습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var globalVar = "I'm global";
function outerFunction() {
var outerVar = "I'm outer";
function innerFunction() {
var innerVar = "I'm inner";
console.log(innerVar); // "I'm inner"
console.log(outerVar); // "I'm outer"
console.log(globalVar); // "I'm global"
}
innerFunction();
}
outerFunction();
- 위의 예시에서 내부 함수인 innerFunction은 외부 함수인 outerFunction의 변수와 전역 변수에 접근할 수 있는데, 이러한 구조는 코드를 예측 가능하고 이해하기 쉽게 만듭니다.
2. 클로저 구현
: 렉시컬 스코프는 내부 함수가 외부 함수의 변수에 접근할 수 있기 때문에 클로저를 쉽게 구현하여 사용하며, 데이터를 보호하고 비공개 상태를 유지할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
function createCounter() {
var count = 0;
return function() {
count++;
return count;
};
}
var counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
- 위의 예시는 클로저를 사용하여 카운터 함수를 구현한 것으로 createCounter 함수는 클로저를 반환하여 내부 변수인 count를 보호하고 외부에서 접근할 수 없도록 합니다. 클로저를 사용하여 비공개 상태를 유지하고 함수를 반환함으로써 외부에서 안전하게 카운터를 증가시킬 수 있습니다. 클로저가 나타나는 부분은 createCounter 함수 내에서 반환되는 익명 함수입니다.
단점
1. 유연성 부족
: 렉시컬 스코프는 함수를 선언한 위치에 따라 스코프가 결정되므로, 실행 컨텍스트에 따라 동적으로 스코프를 변경할 수 없어 경우에 따라 유연성이 부족할 수 있습니다.
1
2
3
4
5
6
7
8
function testScope() {
if (true) {
var x = 10;
}
console.log(x); // 10
}
testScope();
- 위의 예시에서 x 변수는 if 블록 내에서 선언되었지만, 함수 스코프에 속하므로 함수 내 어디서든 접근할 수 있습니다. 이는 렉시컬 스코프의 한계로 인해 실행 컨텍스트에 따라 동적으로 스코프를 변경할 수 없음을 보여줍니다.
2. 디버깅 어려움
: 코드의 실행과 상관없이 함수가 선언된 위치에 따라 스코프가 결정되기 때문에 만약 코드가 복잡하고 중첩된 함수가 많아진다면 스코프 체인을 이해하고 디버깅하기 어려울 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var a = 10;
function outerFunction() {
var b = 20;
function innerFunction() {
var c = 30;
console.log(a); // 10
console.log(b); // 20
console.log(c); // 30
}
innerFunction();
}
outerFunction();
- 위의 예시처럼 함수 내부의 변수들이 어디에서 선언되었는지를 파악하기 위해서는 코드의 구조를 이해해야 합니다. 이러한 변수들이 많아진다면 이해하기 어려워져 결국 디버깅의 어려움으로 이어지게 됩니다.
이렇게 오늘은 자바스크립트의 스코프(scope) 중 렉시컬 스코프에 대해 알아봤는데요,
오늘 정리한 내용도 면접을 준비할 때 나올 수 있는 질문인만큼 미리미리 숙지해서 알아두면 좋을 것 같네요.
그럼 다음엔 또 다른 면접 정보들을 가져와보도록 하겠습니다 😁!