본문 바로가기
JavaScript

[JavaScript] var로 선언된 변수가 선언되기 이전에도 접근할 수 있는 이유 (feat. 스코프&호이스팅)

by hotdog7778 2023. 7. 26.

변수 선언 키워드인 var에 대한 아래 설명을 보고 궁금해서 공부한 내용을 작성합니다.

 " var : 함수 스코프를 가지며, 호이스팅(hoisting)으로 인해 변수가 선언되기 이전에도 접근할 수 있습니다. " 

 

1. 스코프

스코프 : 유효한 참조 범위

ex) 함수내부에 선언된 변수가, 함수 내부에서만 참조가 가능하다면 >> 해당 변수의 스코프는 함수 내부

  • 함수 내부에서 var로 선언된 변수는 지역 변수의 스코프를 가집니다. 하지만 그외에서 var로 선언된 변수는 전역변수의 스코프를 가집니다. (따라서 함수내부가 아닌 if, for 문 내부에서 선언되더라도 전역변수의 스코프를 가집니다.)
  • 모든 블록 내부에서 let과 const로 선언된 변수는 다 지역변수의 스코프를 가집니다. (if, for문 등에서도)

 

2. 호이스팅

호이스팅 : 말 그대로 끌어올려진다는 의미를 가집니다.

JavaScript에서 호이스팅(hoisting)이란, 인터프리터가 변수와 함수의 선언 전에 메모리 공간을 미리 할당하는 것을 의미합니다.

 - 미리할당 한다는 것 = 코드가 맨위로 올라간다 = 호이스팅 된다. 저는 우선 이렇게 이해하고 있습니다.

 - 이때, 호이스팅 되는 범위는 해당 함수나 변수의 스코프의 상단 입니다.

 - JavaScript는 초기화를 제외한 선언만 호이스팅합니다. (예외로 var 선언 시 undefined, 그 외에는 초기화하지 않음)

 - 변수,함수 둘다 호이스팅시 변수를 더위로 위치시킨다.

 

 

2-1. 변수 호이스팅

자세히는, 자바스크립트에서는 코드실행 전 자바스크립트 엔진이 ‘코드 평가 과정’을 거칩니다.

‘코드 평가 과정’ 에서 변수 선언을 미리 실행해 두기 때문에, 뒤에 선언된 변수도 앞의 코드에서 참조할 수 있게 됩니다.

 

그런데, var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화합니다.

반면 let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.

이로 인해 var 키워드로 선언된 변수가 호이스팅 될 경우 특이점이 발생합니다. 

 

var 호이스팅

console.log(a); // undefined 출력
var a = 10;

ReferenceError 가 발생하지 않고 undefined 가 나오는 이유는 호이스팅이 발생했기 때문이고 즉, 위 코드는 아래와 같은 의미를 지닙니다. 이 과정을 코드로 표현하면 아래와 같은 의미를 지닙니다.

var a = undefined;
console.log(a); // undefined 출력
var a = 10;

 

 

var선언이 함수 내부에서 이루어져 지역변수의 스코프를 가지게 될 때 발생하는 호이스팅 케이스도 알아보겠습니다.

var x = 'outer scope';
(function() {
  console.log(x); // outer scope 출력
}());


// 코드에서 사용한 구문은 IIFE(Immediately-invoked function expression: 즉시 작동하는 함수식)라는 구문입니다. 
// "이 안에 들어있는 코드를 바로 실행해라" 라는 표현으로 이해하시면 되겠습니다.

위 코드는 정상적으로 전역변수 x 를 함수 내부에서 사용 하기때문에 'outer scope'를 출력합니다.

 

 

var x = 'outer scope';
(function() {
  console.log(x); // 전역변수인 x가 있지만 undefined를 출력합니다.
  var x = 'inner scope';
}());

위 코드에서는, 변수 x는(1줄에 전역변수가 있음에도) undefined 이 출력됩니다.

4번째 줄의 변수 x는 함수레벨 스코프로 함수내부에서 선언되었고, 지역변수로써 인정받습니다.  그래서, 참조 가능한 범위인 스코프는 함수 내부인 { } 속 입니다. 이 때 호이스팅이 발생합니다.

 

그래서 위 코드는 아래 코드와 같은 의미를 지닙니다.

var x = 'outer scope';
(function() {
  var x = undefined;
  console.log(x); // undefined 출력 
  x = 'inner scope';
}());

 

 

let / const 호이스팅

이부분은 이해가 되는 부분을 정확히 설명 하기힘들어 결론만 작성 합니다.

 - 호이스팅이 발생한다.

 - 하지만, const/let은 TDZ에 영향을 받아 선언 전에 변수를 사용하는것을 허용하지 않습니다. 그렇기 때문에 호이스팅이 발생하지 않는 것처럼 보입니다.

 

** 변수 스코프의 맨 위에서 변수의 초기화 완료 시점까지의 변수는 "시간상 사각지대"(Temporal Dead Zone, TDZ)에 들어간 변수라고 표현합니다.

 

 

 

3-1. 함수 호이스팅

 - 함수 선언식 : 호이스팅이 발생합니다.

 - 함수 표현식 : 호이스팅이 발생하지 않습니다.

 

 

함수 선언식 호이스팅

console.log(declarationFunc('함수선언식'));  // "함수 선언식" 출력


// 함수 선언식 사용
function declarationFunc(name) {
    return name;
}

위 코드는 호출 -> 선언 순으로 작성 되었지만, 호이스팅이 발생해서 정상적으로 함수를 호출 합니다. (즉, 실제동작은 선언 -> 호출 과 같습니다.)

 

 

함수 표현식 호이스팅

console.log(expressionFunc('함수표현식')); // TypeError: expressionFunc is not a function 출력

// 함수 표현식 사용
var expressionFunc = function (name) {
    return name;
}

위 코드에서, var키워드 때문에 변수 호이스팅이 이루어지면서 expressionFunc이 초기화되고 TypeError가 발생합니다.
var가 아닌 let / const 키워드 사용해서 함수 표현식을 작성하면 호이스팅이 일어나지 않아 ReferenceError 발생합니다.

 

 

 

 

요약

 - 함수선언식 사용시 호이스팅이 이루어 지는것을 인식하자.

 - var는 사실 사용을 거의하지 않는다고 합니다.

 - 변수의 호이스팅은 var / let / const 에서 모두 발생하지만, let과 const 는 TDZ의 영향을 받아 호이스팅 발생x 처럼 보인다.

 


 

 

참고 사이트.

https://tecoble.techcourse.co.kr/post/2021-04-25-hoisting/

https://curryyou.tistory.com/192

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EB%B3%80%EC%88%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85

https://medium.com/korbit-engineering/let%EA%B3%BC-const%EB%8A%94-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85-%EB%90%A0%EA%B9%8C-72fcf2fac365