본문으로 건너뛰기
김신건의 로그

[Javascript] 스코프 체인

· 수정 · 📖 약 2분 · 737자/단어 #javascript #scope #lexical #fundamentals
JS 스코프 체인, JavaScript scope chain, JS scope

정의

스코프 체인 (Scope Chain) 은 변수 식별자를 해결할 때 따라가는 중첩된 Lexical Environment 의 연결 구조. 안쪽 스코프에서 찾지 못한 변수를 바깥 스코프로 차례로 검색.

시각화

flowchart LR
    inner["inner 스코프"]
    outer["outer 스코프"]
    global["global 스코프"]
    inner -->|"변수 없으면 위로"| outer
    outer -->|"변수 없으면 위로"| global
    global --> result["발견 / ReferenceError"]
global scope
└─ outer function scope
    └─ inner function scope
        └─ block scope { let x = 1 }

변수 lookup 은 inner → outer → global 순서. 가장 가까운 스코프에서 발견하면 즉시 반환.

기본 예

const a = 'global';

function outer() {
    const b = 'outer';

    function inner() {
        const c = 'inner';
        console.log(a, b, c);   // 'global outer inner'
    }
    inner();
}
outer();

inner 에서 a 를 찾을 때:

  1. inner 스코프 → 없음
  2. outer 스코프 → 없음
  3. global 스코프 → ‘global’ 발견

정적 (Lexical) 스코프

JavaScript 는 lexical scope, 즉 함수가 정의된 위치 가 스코프를 결정. 호출 위치는 무관.

const x = 'global';

function foo() {
    console.log(x);    // 'global' (정의 위치 기준)
}

function bar() {
    const x = 'local';
    foo();             // 'global' (호출 위치 무관)
}
bar();

자세히는 Lexical Environment 참고.

블록 스코프 (ES6)

function foo() {
    const x = 1;
    if (true) {
        const x = 2;    // 새 블록 스코프
        console.log(x); // 2
    }
    console.log(x);     // 1
}

let/const 는 블록 단위, var 는 함수 단위.

클로저와의 관계

함수가 자기 정의 위치의 Lexical Environment 를 들고 다니는 것이 클로저.

function makeCounter() {
    let count = 0;
    return () => ++count;
}

const counter = makeCounter();
counter();    // 1
counter();    // 2
counter();    // 3

내부 화살표 함수가 makeCounter 의 LE 를 참조 → count 살아있음.

scope chain 의 lookup 순서

let x = 1;
function foo() {
    let x = 2;
    function bar() {
        let x = 3;
        console.log(x);     // 3 (가장 가까운 정의)
    }
    bar();
}
foo();

가장 가까운 스코프부터 검색, 발견하면 즉시 사용 (shadowing).

global vs module 스코프

환경최상위 스코프
브라우저 ES modulemodule 스코프
브라우저 일반 scriptglobal 스코프
Node.js CommonJSmodule 스코프
Node.js ES modulemodule 스코프
// ES module
const x = 1;     // module 스코프
// window.x → undefined (global 에 attach 안 됨)

IIFE 패턴

즉시 실행 함수 표현식. 새 스코프를 만들어 전역 오염을 방지.

(function () {
  const privateVar = 'inside';
  // privateVar 는 이 스코프 안에만 존재
})();
// privateVar → ReferenceError (바깥 접근 불가)

ES Modules 이전, 전역 네임스페이스 오염 방지의 표준 패턴. 현재는 ES module 로 대체됨.

// IIFE 로 private 상태 만들기
const counter = (function () {
  let count = 0;
  return {
    inc: () => ++count,
    get: () => count,
  };
})();

TDZ (Temporal Dead Zone) 와 스코프 체인

let/const 는 선언 전에 접근하면 ReferenceError (TDZ).
스코프 체인 탐색 결과 안쪽 스코프에서 선언이 있으면 바깥 값이 아니라 TDZ 에 걸린다.

let x = 1;
function foo() {
    console.log(x);   // ReferenceError (TDZ, 바깥 x 무시)
    let x = 2;
}
foo();

안쪽 let x 가 호이스팅으로 foo 스코프 상단으로 끌어올려지고, 초기화 전 접근 → TDZ.
바깥 x = 1가려버리고 (shadow) TDZ 에 진입.

스코프 체인 vs 프로토타입 체인

스코프 체인프로토타입 체인
탐색 대상변수 / 식별자객체의 프로퍼티
방향정의 위치 기반 (정적)객체의 __proto__ 링크 (동적)
언어 메커니즘Lexical Environment객체 상속
global scope → undefinedObject.prototype → null
// 프로토타입 체인 예
const parent = { greet() { return 'hello'; } };
const child = Object.create(parent);
child.greet(); // 'hello' (child 에 없어서 parent 에서 찾음)

with 와 eval (피해야 할 것들)

with (obj) { ... }    // 스코프 체인에 동적으로 obj 삽입
eval('var x = 1;')    // 호출 스코프에 변수 삽입 (strict 모드 외)

둘 다 스코프 체인을 예측 불가능하게 만들어 최적화 방해. 사용 금지.

함정

1. 변수 호이스팅 + 스코프

let x = 1;
function foo() {
    console.log(x);   // ReferenceError (x 의 호이스팅된 TDZ)
    let x = 2;
}
foo();

안쪽 let x 가 호이스팅되어 바깥 x 를 가림.

2. 클로저의 성능

모든 함수가 자기 LE 를 참조. 너무 많은 변수를 closure 로 가두면 메모리 압박. 진짜 불필요한 변수는 외부로.

3. global 오염

// 실수로 var 빼먹기 (sloppy 모드)
function foo() {
    x = 1;   // var/let/const 없이 → global 에 추가됨!
}

strict 모드에서는 ReferenceError. 항상 'use strict' 또는 ES module 사용.

4. 동적 스코프와 혼동

JavaScript 는 동적 스코프가 아님. this 는 동적으로 결정되지만, 변수 참조는 정적 (lexical).

function f() {
  console.log(msg); // 정의 위치 기준 탐색
}
// f 를 어디서 호출하든 msg 참조 위치는 f 정의 당시 스코프

참고

이 글의 용어 (5개)
[Javascript] 클로저javascript
정의 클로저 (Closure): 함수가 자신이 정의된 시점의 외부 변수들을 계속 참조할 수 있는 성질. 함수가 일급 객체 () 인 언어의 자연스러운 결과. 메커니즘은 + 함수 객…
[Javascript] 호이스팅 (Hoisting)javascript
정의 호이스팅 (Hoisting) 은 JavaScript 엔진이 코드를 실행하기 전 바인딩 생성 단계 에서 스코프 내의 선언을 파악하고 등록하는 메커니즘이다. 마치 선언이 스코프…
[Javascript] Lexical Environmentjavascript
정의 Lexical Environment (어휘적 환경) 는 ECMAScript 명세 (§9.1) 가 정의한 내부 객체. 함수가 호출될 때마다 새로 만들어지며, 이 호출의 변수들…
[Javascript] Prototype Chainjavascript
정의 JavaScript 의 모든 객체는 (내부 슬롯) 을 가진다. 속성 lookup 시 자신에게 없으면 prototype chain 을 따라 올라가며 검색. 접근 함수의 pro…
[Javascript] var / let / constjavascript
정의 JavaScript 의 3 가지 변수 선언 키워드. | 키워드 | 스코프 | 재할당 | 재선언 | 호이스팅 | |:---|:---|:---:|:---:|:---| | | f…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기