Frontend

[Javascript] 변수, 호이스팅, TDZ

pebblepark 2022. 3. 7. 15:53

변수의 종류

  1. let
  2. const
  3. var

 

var는 한번 선언된 변수를 다시 선언할 수 있다.

// ✅
var name = 'Mike';
console.log(name); // Mike

var name = 'Jane';
console.log(name); // Jane

// ❌
let name = 'Mike';
console.log(name); // Mike

let name = 'Jane'; // error! (동일한 이름으로 재선언 불가)
console.log(name);

 

var는 선언하기 전에 사용할 수 있다.

console.log(name); // undefined
var name = 'Mike';

 

위의 예제에서 에러가 발생하지 않는다. var는 아래처럼 동작하기 때문이다.

var name;
console.log(name); // undefined
name = 'Mike'; // 할당

var로 선언한 모든 변수는 코드가 실제 이동되지 않지만 최상위로 끌어 올려진 것처럼 동작한다. 이를 호이스팅이라고 한다. 해당 코드 실행 결과, 콘솔에는 undefined가 찍힌다. 이는 선언은 호이스팅되지만 할당은 호이스팅되지 않았기 때문이다. 따라서 변수 선언만 최상단으로 올려진 것이고 할당은 해당 자리(세번째 줄)에서 처리된다.

호이스팅(Hoisting) : 스코프 내부 어디서든 변수 선언은 최상위에 선언된 것처럼 행동

 

같은 상황에서 let은 에러가 발생한다.

console.log(name); // ReferenceError
let name = 'Mike';

이는 Temporal Dead Zone, 이하 TDZ 영역에 있는 변수들은 사용할 수 없기 때문이다. TDZ는 선언이 호이스팅 되더라도 초기화(초기 할당)가 이루어지기 전까지는 해당 변수에 접근할 수 없는 구역을 지칭한다.

 

Tmporal Dead Zone(TDZ): 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 말한다.
/** Temporal Dead Zone **/
console.log(name);       // 선언만 호이스팅되고 초기화는 x
/** Temporal Dead Zone **/

const name = 'Mike'; 	// 함수 선언(호이스팅 됨) 및 초기화
console.log(name); 		// 사용 가능

 

letconstTDZ 의 영향을 받는다. 즉, 초기화 이전까지 해당 변수에 접근할 수 없다. 이를 통해 코드를 예측 가능하게 만들고 잠재적인 버그를 줄일 수 있다.

// ✅
let age = 30;

function showAge() {
console.log(age);					
}
showAge();

// ❌
let age = 30;

function showAge() {// function scope
/** Temporal Dead Zone **/
console.log(age);
/** Temporal Dead Zone **/
let age = 20;
}                   // function scope
showAge();

 

호이스팅은 스코프 단위로 일어난다. 여기서 스코프scope는 function 함수 내부이다. TDZ가 존재하는 두번째 경우를 살펴보자.

  1. let으로 선언한 두번째 age변수가 호이스팅을 일으킨다.
  2. 따라서 초기화가 아직 이루어지지 않은, 콘솔로 출력하는 부분에서 RefferenceError가 발생한다.
  3. 만약 호이스팅이 일어나지 않았다면 함수 바깥에서 선언한 age가 30으로 출력될 것이다.

 

 

변수 생성 과정

변수는 3단계의 생성과정을 거친다

  1. 선언
  2. 초기화
  3. 할당

 

var

  1. 선언 및 초기화 단계 (초기화: undefined를 할당해주는 단계)
  2. 할당 단계

var는 선언과 동시에 초기화된다. 따라서 할당 전에 호출하면 에러를 내지 않고undefined를 반환한다.

 

let

  1. 선언 단계
  2. 초기화 단계
  3. 할당 단계

let은 초기화 단계와 선언 단계가 분리돼서 이루어진다. 호이스팅되면서 선언 단계가 이루어지지만 초기화단계는 실제 코드에 도달했을 때 발생하므로ReferenceError가 발생한다.

 

const

  1. 선언 + 초기화 + 할당

선언과 할당이 동시에 이루어진다. 따라서 const는 값 변경이 불가능하다.

 

 

스코프

  • var : 함수 스코프(function-scoped)
  • let, const: 블록 스코프(block-scoped)

 

블록 스코프는 모든 코드 블록에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 외부에서 접근할 수 없다. 즉, 코드 내부에서 선언한 변수는 지역변수이다. 여기서의 코드 블럭은 함수, if 문, for 문, while 문, try/catch 문 등을 말한다.

function add() {
// Block-level Scope
}
if() {
// Block-level Scope
}
for(let i=0;i<10;i++) {
// Block-level Scope
}

 

반면, 함수 스코프는 함수 내에서 선언된 변수만 그 지역 변수화 된다. 예를 들어 if문 내에서 선언한 변수는 구문 밖에서도 사용이 가능하다. 하지만 letconst는 블록 스코프이기 때문에 중괄호를 벗어나는 순간 사용이 불가능하다.

const age = 30;
if(age>19) {
var txt = '성인';
}
console.log(txt); // '성인'

 

var도 함수 내부에서 선언되면 함수 외부에서 사용이 불가능하다. 유일하게 벗어날 수 없는 스코프가 함수라고 생각하면 된다.

function add(num1, num2) {
var result = num1 + num2;
}
console.log(result); // ReferenceError

 

참고: 자바스크립트 중급 강좌 #1 - 변수, 호이스팅, TDZ(Temporal Dead Zone)