본문 바로가기
CS 질문

[Deep Dive CS- Q12, Q13] Scope

by 민챙이_99 2025. 12. 16.

Q12. 아래 코드의 실행 결과를 예측하고, var와 let의 동작 차이를 '렉시컬 환경' 관점에서 설명해주세요.

// Case A
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log('A:', i), 100);
}

// Case B
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log('B:', j), 100);
}

 

[Case A (var) 분석]

  • 결과: 3, 3, 3
  • 설명: var는 함수 스코프(Function Scope)를 따릅니다. 루프가 돌 때마다 새로운 스코프가 생기는 것이 아니라, for문이 속한 상위 스코프(함수 혹은 전역)에 있는 단 하나의 변수 i를 공유합니다.
    • setTimeout의 콜백 함수(클로저)들은 모두 이 유일한 렉시컬 환경의 i를 참조(Reference)합니다.
    • 콜백이 실행될 때는 이미 루프가 끝나 i가 3이 된 상태이므로, 모두 3을 출력합니다.

[Case B (let) 분석]

  • 결과: 0, 1, 2
  • 설명: let은 블록 스코프(Block Scope)를 따릅니다. for문은 반복할 때마다 새로운 렉시컬 환경(새로운 방)을 생성합니다.
    • 각 반복(Iteration)마다 독립적인 변수 j가 생성되고, setTimeout의 콜백 함수는 자신이 생성될 당시의 고유한 렉시컬 환경을 힙(Heap)에 저장(Capture)해둡니다.
    • 나중에 콜백이 실행될 때, 각자의 환경에 저장된 0, 1, 2를 정확히 가져옵니다.

 

Q13. 렉시컬 스코프(Lexical Scope)와 다이나믹 스코프(Dynamic Scope)의 차이는 무엇이며, 자바스크립트의 this는 어느쪽을 따르나요? 

일반 함수에서의 this는 다이나믹 스코프(Dynamic Scope)의 원리를 따르고, 
화살표 함수(Arrow Function)에서의 this는 렉시컬 스코프(Lexical Scope)를 따릅니다.

구분 렉시컬 스코프(Lexical Scope) 다이나믹 스코프(Dynamic Scope)
기준 선언된 위치 호출된 위치(Run-time)
JS 변수 O (스코프체인) X
JS this 화살표 함수 (Arrow Function) 일반 함수(function)
특징 예측이 쉽고 코드 분석이 용이함 유연하지만 예측이 어려움

 

A. 렉시컬 스코프 (Lexical Scope / Static Scope)
- 별명: 정적 스코프 (Static Scope)
- 결정 시점: 코드를 작성하는 순간 (Compile/Author Time)
- 원리: 함수가 "어디서 선언(정의)되었는지"에 따라 상위 스코프가 결정됩니다. 누가 호출했는지는 전혀 중요하지 않습니다.
- 자바스크립트: 자바스크립트의 변수 검색(Scope Chain)은 100% 렉시컬 스코프입니다.

B. 다이나믹 스코프 (Dynamic Scope)
- 별명: 동적 스코프
- 결정 시점: 코드가 실행되는 순간 (Runtime)
- 원리: 함수가 "어디서 호출되었는지"에 따라 상위 스코프가 결정됩니다. 즉, Call Stack 바로 아래에 있는 함수가 내 부모가 됩니다.
- 자바스크립트 : 일반함수의 this

 

+ 자바스크립트는 기본적으로 렉시컬 스코프(선언한 위치에서 상위 스코프가 결정되는) 언어입니다. 그래서 클로저(Closure)같은 강력한 기능이 가능합니다. 

렉시컬 환경이랑 클로저랑 무슨 연관 인데요??
- 자바스크립트가 네가 태어난 곳을 절대 잊지 않는다(렉시컬 스코프)라는 규칙을 정했기 때문에, 엔진은 함수가 어디로 가든 원천지의 데이터를 함께 싸서 보내주기 때문에 그렇습니다. 만약 렉시컬 스코프가 아니라 다이나믹 스코프였다면, 매번 호출할때마다 결과 값이 달라지거나 값을 참조할 수 없는 상황이 이루어져 클로저라는 정보은닉의 함수가 아니라 그냥 값을 예측할 수 없기 때문에 안티패턴(Anti-pattern) 취급을 받았을 것입니다.

 

하지만, 자바스크립트에서는 예외가 있었습니다. 그 예외가 일반함수의 this 입니다. 이 녀석은 다이나믹 스코프(호출 주체에 따라 바뀜)처럼 동작해서 개발자들에게 혼란을 주었습니다. 이를 해결하기 위해 bind, call, apply가 존재했고, 개발자들이 "제발 this 좀 고정시키자!" 라는 니즈 때문에 ES6부터는 아예 렉시컬 스코프를 따르는 화살표 함수가 도입되어 혼란을 잠재웠습니다. 

화살표 함수는 자체적인 this를 가지고 있지 않기 때문에 선언된 위치의 상위 스코프의 this를 그대로 가져다 씁니다.