스코프
개요
스코프는 변수라는 양을 가둬놓는 울타리와 같다
오늘 회사 앞에 양이 왔다 (진짜임)

스코프란?
스코프란 유효범위로 특정 변수를 참조할 수 있는 범위 라고 생각하면 된다
function add(x, y) {
console.log(x, y) // 2 5
return x + y
}
add (2, 5)
console.log(x, y); // 레퍼런스 에러
변수는 자신이 선언된 위치에 의해 자신이 유효한 범위를 뜻함
그래서 이렇게 동작함
var x = 'global';
function foo() {
var x = 'local';
console.log(x); // local
}
foo()
console.log(x); //global
이렇게 코드가 어떤 변수를 참조해야 할 것인지를 결정해야하는데 이를 식별자 결정 이라 한다.
만약 스코프라는 개념이 없다면 같은 이름을 갖는 변수는 충돌을 일으키므로 프로그램 전체에서 하나밖에 사용할 수 없을것이다.
왜 그런지는 한번 직접 생각해보자

스코프의 종류
전역 스코프
코드의 가장 바깥 영역임
var x = 'global'; // 이게 전역이고
function foo() {
var x = 'local'; // 이게 지역임
console.log(x);
}
foo()
console.log(x);
전역에 변수를 선언하면 어디서든지 참조할 수 있음
지역 스코프
지역스코프는 지역스코프다. 이때 지역이란 함수 몸체 내부를 말함
지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효함
function foo() {
var x = 'local';
function localFn() {
console.log(x) // local
}
localFn();
console.log(x); // local
}
foo()
이런 현상을 스코프 체인이라고 함
스코프 체인
이것도 어렵지 않다.
변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 탐색한다
이거 완전 재귀아니냐?
정답: 스펙(ECMA-262)은 진짜 재귀로 정의돼있음.
근데 재귀 호출 = 콜스택 프레임 쌓임 = 비용 때문에 엔진은 그냥 while 루프로 outer 포인터 따라간다고 함.
V8은 한 번 찾은 위치를 캐싱(IC)까지 해버림 ㅋㅋ (레전드)
// ECMA-262
GetIdentifierReference(env, name):
if env == null: return unresolvable
if env.HasBinding(name): return reference
outer = env.OuterEnv
return GetIdentifierReference(outer, name) ← 자기 자신 호출
// 엔진 내부 의사 코드
let env = currentEnv;
while (env !== null) {
if (env.has(name)) return env.get(name);
env = env.outer;
}
throw ReferenceError;
사실상 부자 관계로 이뤄진 상속과 유사하다 보면 됨
함수 레벨 스코프
지역 스코프는 코드 블록이 아닌 함수에 의해서 생성된다
여기서 환장해부릴 사실
JAVA, C, Rust를 비롯한 대부분의 프로그래밍 언어는 함수 몸체만이 아니라 모든 코드블록 (if, for, while, try/catch 등)이 지역 스코프를 만든다.
이를 블록 레벨 스코프라고 함
자바스크립트는이마저귀찮아서정녕함수로만지역스코프를생성한단말이냐네이놈

var x = 1;
if (true) {
var x = 10;
}
console.log(x); // 10 ㅋㅋ 아오
var i = 10;
for (var i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
console.log(i); // 5 ㅋㅋ 아오
위 예제들을 보면 알수있다싶이 블록 레벨 스코프가 생성되지 않아 x 가 잡아묵힌 상황이다
진짜 이거 어떡하냐
렉시컬 스코프
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
자바스크립트는 함수를 어디서 정의했는지에 따라 상위 스코프를 결정하기 때문에 두 함수의 출력은 모두 1이 된다
이 방식을 렉시컬 스코프, 또는 정적 스코프 라고 하는데 동적 스코프 방식과는 다르게 함수 정의가 평가되는 시점에서 상위 스코프가 정적으로 결정된다
왜 이런 방식을 체택했을까??
호출하는 위치마다 결과가 바뀌면 머리깨짐 ㅋㅋ
그리고 함수가 자기 선언 위치를 기억해야 클로저가 됨. 이거 없으면 콜백이고 뭐고 다 안돌아감
성능적으로도 이득임. 컴파일 타임에 변수 위치를 미리 계산해두니깐 런타임엔 바로 그 자리 가서 꺼내면 됨.
동적이었으면 호출할때마다 콜스택 거슬러올라가며 변수 찾아야됨 → 당연히 느림
참고 자료
- 모던 자바스크립트 Deep Dive 13장
- 함수 — 12장, 함수와 스코프의 관계
- 렉시컬 스코프 — 함수 선언 위치에 따른 상위 스코프 결정 방식
- var let const — 함수 레벨 vs 블록 레벨 스코프
'코딩딩 > Javascript' 카테고리의 다른 글
| 날것 - let, const 키워드와 블록 레벨 스코프 (0) | 2026.05.26 |
|---|---|
| 날것 - 전역 변수의 문제점 (0) | 2026.05.19 |
| 날것 - 함수 (0) | 2026.05.12 |
| 날것 - 원시 값과 객체의 비교 (1) | 2026.04.15 |
| 날것 - 객체 리터럴 (0) | 2026.04.08 |