logo
Javascript

변수 생성 과정, 호이스팅 정리

문성석2021년 8월 10일

thumbnail


변수란?

하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름을 말한다. 아무리 복잡한 어플리케이션이라도 실행되는 흐름은 데이터를 받고, 처리하고, 출력하는 것이 전부이다. 프로그래밍 언어에서 변수는 이러한 데이터를 관리하기 위한 핵심 개념이다.



변수를 이용하는 이유는?

메모리를 직접 건드리는 것은 시스템의 치명적 오류를 발생시킬 가능성이 높다. 게다가 메모리에 저장된 값의 주소가 매번 바뀌기 때문에 재사용이 힘들다. 변수를 사용하면 값을 저장할 수 있는 공간을 확보하고 식별할 수 있다.



변수 선언, 초기화, 할당 단계

변수가 생성되는 과정은 선언, 초기화, 할당. 총 3단계를 거쳐 진행이 된다.


1) 변수 선언

변수 선언 단계에서는 값을 저장하기 위한 메모리 공간을 확보한다. 그리고 저장한 메모리를 식별하기 위한 변수 이름을 설정하는 것까지 변수 선언 단계에서 진행된다.


2) 변수 초기화

변수 선언 단계를 거쳐 메모리 공간을 확보한 후에는 해당하는 메모리 공간에 undefined를 할당하여 초기화한다.


3) 변수 할당

초기화 단계까지 마쳐 undefined가 할당된 변수에 원하는 값을 재할당한다.



호이스팅이란?

소스코드에서 선언된 모든 식별자(변수, 함수, 클래스)들이 유효범위 내 최상단에 마치 끌어올려진 것처럼 동작되는 자바스크립트 고유의 특징이다.



호이스팅이 일어나는 과정

자바스크립트 엔진이 코드들을 평가하면서 호이스팅 적용이 가능한 모든 식별자(변수, 함수, 클래스 등)들을 실행 컨텍스트 내부에 저장을 한다. 이 과정에서 식별자들을 실행 컨텍스트가 관리하는 스코프(렉시컬 환경의 환경 레코드)에 등록한다.


예시 코드와 함께 알아보자.

console.log(test);
var test = 1;

자바스크립트 엔진이 코드를 평가하는 과정에서 var test;가 실행 컨텍스트가 관리하는 스코프에 저장이 된다. 이때 test 변수는 선언, 초기화 단계가 동시에 진행되어 undefined 값을 가지고 있다.


execution context


평가 과정이 끝나면, 이미 실행되었던 코드들을 제외한 나머지 코드들을 실행한다. 실행되는 순서대로 예시 코드를 나타내 보자면 다음과 같다.

var test; -> 선언, 초기화 단계를 마쳐서 undefined를 가지고 있음
console.log(test) // undefined
test = 1;
 
선언, 초기화 단계를 마치고 마지막으로 값을 할당한다.

위와 같이 var test는 호이스팅이 적용되어 유효범위 최상단에 끌어올려지듯이 코드가 실행된다.



추가 정리

TDZ(Temporal Dead Zone)란?

TDZ는 일시적 사각지대라고 하며, 변수가 가지고 있는 스코프 시작 지점부터 초기화 시작 지점까지 참조할 수 없는 곳이 있는데 이 구간을 TDZ라고 부른다.


이 TDZ는 let과 const에서만 존재하며, var를 사용한다면 TDZ는 존재하지 않는다. 이는 호이스팅 방식의 차이 때문인데, 아래 예제 코드에서 확인해보자.

console.log(test); // undefined
var test = 1;

var로 선언한 변수는 선언, 초기화 단계가 동시에 이루어진다. 때문에 test를 참조하는 시점에 undefined가 이미 할당이 되어진 상태라 참조 오류가 발생하지 않는다.

console.log(test); // Uncaught ReferenceError
 
let test = 1;
const test2 = 1;

그러나 let, const로 선언한 변수는 선언 단계와 초기화 단계가 분리되어있다. 따라서 test를 참조하는 시점에 초기화가 되어있지 않은 상태이기 때문에 참조 오류가 발생하게 된다. 이 참조 오류가 발생하는 구간, 즉 let, const 변수가 가지고 있는 스코프 시작 지점부터 초기화 시작 지점까지의 구간을 TDZ라고 부른다.



var와 let, const의 차이점

가장 큰 차이점은 선언 방식의 차이점이다. 각각의 특징들을 정리하면서 확인해보자.


1) var (재선언 가능)

var는 재선언이 가능하다는 특징을 가지고 있다. 때문에 다음과 같이 같은 이름의 변수를 두 번 선언하더라도 에러가 발생하지 않는다.

var a = 1;
var a = 3; 에러 발생 X

프로젝트 규모가 작거나, 간단한 테스트에서라면 재선언을 하면서 편리하게 사용할 수도 있다. 하지만 코드량이 많아지게 된다면, 언제 어디서 선언 됐는지 파악하기 힘들뿐더러 의도치 않게 값이 변경될 가능성도 있다.

이러한 문제점을 해결하기 위해 자바스크립트 es6 문법에서 새롭게 등장한 것이 let과 const이다.


2) let (재선언 불가)

let은 재선언은 불가하지만 재할당이 가능하여 변수를 선언한 이후에 언제든 값을 변경할 수 있다.

let test = 1;
test = 3;
console.log(test); // 3

3) const (재선언 불가)

const는 재선언, 재할당 모두 불가능하여 변수를 선언하고 초기에 할당된 값을 변경할 수 없다.

const test = 1;
test = 3; // Uncaught TypeError: Assignment to constant variable.

참고

모던 자바스크립트 Deep Dive