스코프와 호이스팅

2025. 1. 26. 11:33웹프로그래밍/JavaScript

 

스코프는 변수가 어떤 것을 참조하는지를 결정하는 규칙 모음이다.

보통 중괄호({})로 표현하며, 전역스코프, 함수스코프, 블록스코프 등이 있다. ( 중괄호라고 해도 class 선언, 객체 선언, switch 등에서 사용하는 중괄호는 당연히 스코프가 아니다.)

//전역 스코프
var global_a = 0;
function func(){
    //함수 스코프
    let a = 0;
    var b = 1;
    
    if(true){
        //블록 스코프
        let block_a = 0;
    }
}

 

스코프는 보통 컴파일타임에 결정되는데, 구체적으론 컴파일 중 렉싱 과정에서 결정된다.

렉싱 과정은 토크나이징 이후, 생성된 토큰들에 대한 의미를 부여하는 과정인데, 이 때 어떤 변수가 어디에 작성돼있는지 분석하며, 스코프가 결정되는 것이다.

eval, with 등을 이용해 런타임에 스코프가 변경되는 것을 제외하면, 스코프는 보통 렉싱 과정에서 결정되고,

이러한 스코프를 렉시컬 스코프(lexical scope)라고 부른다.

 

이렇게 컴파일 과정에서 JS 엔진이 스코프를 결정하기 때문에, 변수 / 함수 등의 식별자는 컴파일타임에 특정 스코프에 등록된다.

그래서 호이스팅이라고 불리는 현상이 발생하는데,

 

호이스팅이란, 특정 스코프 내에 선언한 변수/함수가 선언된 위치와 상관없이, 해당 스코프 시작 부분에서 선언한 것마냥 끌어올려지는 현상을 의미한다. (hoist라는 것의 사전적 의미가 raise와 유사한 의미를 가지기 때문에 이런 명칭이 붙었다.)

 

컴파일 과정에서 특정 스코프 내에서 선언된 변수/함수의 식별자가 등록되고,

런타임에서는 그 스코프가 시작되는 시점에 등록된 식별자들이 선언되기 때문에 발생하는 현상인 것이다.

 

var 키워드로 선언한 변수는 함수 스코프에 등록되기 때문에 함수 스코프에 따른 호이스팅이 발생하고,

let/const 키워드로 선언한 변수는 블록 스코프에 등록되기 때문에, 블록 스코프에 따른 호이스팅이 발생한다.

함수 선언문으로 선언한 함수는, JS 명세서상 외부 블록 스코프에 따른 호이스팅이 발생한다. (그런데, 실제로 브라우저 JS엔진에서는 식별자는 외부 함수 스코프에 등록되고, 정의는 외부 블록스코프에 등록된다고 한다.. FiB 패턴 참고)

 

var 키워드로 선언한 변수의 경우엔 어휘적으로 선언된 시점에 초기화가 일어나고, 등록된 스코프 시작 시점엔 undefined로 초기화된다.
함수 선언식으로 선언한 함수는, 스코프 시작 시점에 선언된다.

function testFunc(){
	// 이 시점에 aaa 함수 선언돼있음
	// 이 시점에 testVar는 undefined
   	let a = 2;
   	a = a+2;
   
   	var testVar = 3; // 이 시점에 testVar에 3 대입됨
    
    function aaa(){
    	a += 2;
    }
}

 

let/const 로 선언한 변수는, 동일하게 식별자로 스코프에 등록되지만 var와 다르게 스코프 시작 시점에 undefined로 초기화 되지는 않는다.
(이렇게 설계한 이유: const는 상수화 키워드라 undefined로 초기화되고 나중에 대입되는 것은 말이 안되기 때문에, 선언된 시점에 초기화하고 그 전까지는 접근 못하게 막은 것임. let의 경우엔 const의 방식에 따라 결정했다고 함.)


이 때 스코프 시작부터, 해당 변수가 초기화될 때까지의 시간을 TDZ (temporal dead zone) 라고 한다.

 

let과 const도 스코프에 식별자가 등록되기 때문에 호이스팅은 발생하지만, TDZ 내의 접근을 막은 것이다.

 

이러한 호이스팅은 JS 설계상 의도적이고 명시적인 동작이 아니고, 컴파일 중에 JS가 변수 선언을 처리하는 방식을 설명하기 위한 비유에 가깝다고 한다.

 

'웹프로그래밍 > JavaScript' 카테고리의 다른 글

모듈 패턴  (0) 2025.03.30
클로저  (0) 2025.01.26
JS 파일은 어떻게 실행될까? (with V8 engine)  (0) 2025.01.24