변수 선언문 전에 변수에 접근할 수 있다고?😱
자바스크립트를 처음 배우면서 가장 헷갈렸던 부분에 대해서 정리해보았다.
var
let
const
는 자바스크립트에서 변수를 선언할 때 사용하는 키워드.
변수를 사용하려면 반드시 선언
이 필요하다!
각 키워드 별로 변수 선언 시 어떤 차이점이 있는지 알아보자.
var
키워드로 선언된 변수는 다음과 같은 생명주기를 갖는다.
크게 코드가 한 줄 씩 실행되는 런타임 전
과 런타임 후
로 나눌 수있다.
런타임 전
1. 선언 단계 : 변수 이름을 실행 컨텍스트에 등록해서 자바스크립트 엔진에게 변수의 존재를 알린다.
2. 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.
자바스크립트 엔진에 의해 항상 undefined
로 초기화 되기 때문에 사실상 개발자가 따로 초기화를 해주지 않아도 쓰레기 값
을 만나게 될 일은 없다.
런타임 후
개발자가 할당한 임의의 값으로 실질적 초기화
(재할당)된다.
정확히 말하면 런타임 전에 자바스크립트 엔진에의해 암묵적으로 undefined
로 초기화 된 후, 개발자가 할당한 임의의 값이 재할당
되는 것이므로 실질적 초기화
라는 표현을 사용하였다.
console.log(sum); //undefined
var sum = 0; //변수 선언문
위에서 말했든var
키워드로 선언한 변수는 코드 실행 전 이미 변수가 선언되기 때문에 위와 같이 변수 선언문 전에 변수를 참조할 수 있는 변수 호이스팅
현상이 발생하는 것이다.
let
키워드로 선언된 변수는 다음과 같은 생명주기를 갖는다.
var
키워드와 비교해서 특이한 점은 선언 이후 undefined로 초기화 되기 전까지 변수에 접근할 수 없는 일시적 사각 지대
가 있다는 것이다.
var
와 마찬가지로 let
을 통해 선언한 변수도 런타임 전에 변수 선언이 이루어 진다.
하지만 바로 undefined가 할당되지 않고, 런타임 과정에서 변수 선언문에 도달하게 되면 undefined
가 할당된다.
이때 변수 선언문에 도달하기 전까지 변수에 접근할 수 없는 구간을 일시적 사각 지대
라고 한다.
일시적 사각 지대일 때 변수에 접근할 경우 ReferenceError
가 발생한다.
변수 선언문에 도달한 후, 개발자가 임의의 값을 할당했을 경우에는 다시 해당 값이 재할당된다.
🧩 여기서 중요한 것은 let 키워드로 선언한 변수는 변수 호이스팅이 일어나지 않는 것 처럼 보인다는 것이다.
하지만 사실은 그렇지 않다.
let sum = 0; //전역 변수
{
console.log(sum); //ReferenceError
let sum = 10; //지역 변수
}
만약 정말 let
으로 선언한 변수가 호이스팅이 발생하지 않는다면, 위 예제에서 전역 변수 값인 0을 출력해야한다.
하지만 let
으로 선언한 변수도 호이스팅이 발생하기 때문에 ReferenceError
가 발생하는 것이다.
정리하자면 자바스크립트는 ES6에서 도입된 let
, const
를 포함한 모든 선언(var, function 등)을 호이스팅 한다.
단지 let
, const
의 경우 호이스팅이 발생하지 않는 것 처럼 동작하는 것 뿐이다!
위에서 말했듯이 const
를 사용한 변수 선언도 자바스크립트의 선언문에 포함되기 때문에 호이스팅이 발생한다.
하지만 let
과 마찬가지로 일시적 사각 지대를 갖기 때문에 호이스팅이 발생하지 않는 것 처럼 동작한다.
{
console.log(sum); //ReferenceError
consot sum = 1;
console.log(sum);
}
var
키워드로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정하는 함수 레벨 스코프
를 따른다.
때문에 아래처럼 함수 블록이 아닌 코드 블록에서 변수 선언 시 모두 전역 변수
가 된다.
var sum = 0;
if(true){
var sum = 10; //sum은 전역 변수, 이미 선언된 sum이 있지만, 중복 선언 되었다.
}
console.log(sum); //10
let
const
키워드로 선언한 변수는 모든 코드 블록(함수, if문, for문 등)을 지역 스코프로 인정하는 블록 레벨 스코프
를 따른다.
const sum = 0;
{
const sum = 10;
const max_sum = 100 ;
}
console.log(sum);
console.log(max_sum)
var
키워드로 선언한 변수는 다음과 같이 같은 스코프 내에서 중복 선언이 가능하다.
하지만 변수 중복 선언시 초기화문
유무에 따라서 약간의 차이가 있다.
1. 초기화 문이 있는 변수 (중복) 선언 : 자바스크립트 엔진에 의해 var
키워드가 없는 것 처럼 동작한다.
2. 초기화 문이 없는 변수 (중복) 선언 : 자바스크립트 엔진에 의해 무시된다 : undefined로 초기화 되지 않고, 에러도 발생하지 않는다.
때문에 변수가 이미 선언되어 있는 것을 모르고 중복 선언한 뒤 값을 할당했다면, 의도치 않은 변수 값 변경이라는 부작용이 발생할 수 있어 위험하다.
반면 let
const
로 선언한 변수의 경우 같은 스코프 내에서 중복 선언 할 경우 SyntaxError
가 발생한다.
var
let
키워드로 선언한 변수는 얼마든지 값을 재할당 할 수 있다.
const
키워드로 선언한 변수의 경우 재할당이 금지된다.
따라서 재할당 할 경우 다음과 같은 에러가 발생한다.
🧩 이때 주의할 점은, const
키워드는 재할당
을 금지하는 것이지, 불변
을 의미하는 것이 아니다.
새로운 값을 재할당
하는 것은 불가능 하지만, 배열의 원소를 추가, 삭제 하는 것과 같이 객체를 변경하는 것은 가능하다.
(객체가 변경되더라도 변수에 할당된 참조값(주소값)은 변경되지 않기 때문!)
const
키워드를 사용해 변수를 선언하면 의도치 않은 재할당이 방지되기 때문에 조금 더 안전하다.
따라서, 변수 선언 시 기본적으로 const
를 사용하고 변수 값이 변경되거나 재할당이 필요한 경우에 한정해 let
키워드를 사용하는 것을 추천한다.
참고
모던 자바스크립트 Deep Dive
공부한 내용을 직접 정리한 글이라 잘못된 부분이 있을 수 있습니다. 혹시 잘못된 내용이 있다면 언제든지 알려주세요.🙂