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

[Javascript] 스코프 체인

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

정의

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

시각화

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 안 됨)

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] 클로저javascript
정의 클로저 (Closure): 함수가 자신이 정의된 시점의 외부 변수들을 계속 참조할 수 있는 성질. 함수가 일급 객체 () 인 언어의 자연스러운 결과. 메커니즘은 + 함수 객…
[Javascript] 호이스팅 (Hoisting)javascript
정의 호이스팅 (Hoisting) 은 JavaScript 엔진이 코드 실행 전에 선언을 스코프의 최상단으로 끌어올리는 동작. 단, / 는 로 접근 제한. var 의 호이스팅 엔진…
[Javascript] Lexical Environmentjavascript
정의 Lexical Environment (어휘적 환경) 는 ECMAScript 명세 (§9.1) 가 정의한 내부 객체. 함수가 호출될 때마다 새로 만들어지며, 이 호출의 변수들…
[Javascript] var / let / constjavascript
정의 JavaScript 의 3 가지 변수 선언 키워드. | 키워드 | 스코프 | 재할당 | 재선언 | 호이스팅 | |:---|:---|:---:|:---:|:---| | | f…

💬 댓글

사이트 검색 / 명령어

검색

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