스코프와 호이스팅, var/let/const 비교
스코프란
스코프란 현재의 실행 컨텍스트다.
스코프에 따라 변수에 접근할 수 있는지 여부(가시성)가 정해진다. (참고로 자바스크립트에서 객체와 함수는 모두 변수다.)
스코프는 하이어라키 구조로 되어 있어서 자식 스코프는 부모 스코프에 접근할 수 있지만 그 반대는 안된다.
자바스크립트에는 세 가지 타입의 스코프가 있다.
1. 블락 스코프 (Block scope)
2. 펑션 스코프 (Function scope)
3. 글로벌 스코프 (Global scope)
블락 스코프
블락 { }을 기준으로 하는 스코프다. (함수 블락, if문, for 반복문, while 반복문)
ES6(2015) 이전에는 없었는데 ES6에서 let과 const 키워드 도입과 함께 블락 스코프가 생기게 되었다.
var 키워드로 정의된 변수는 블락 스코프를 갖지 않는다.
{
let x = 2;
var y = 2;
}
console.log(x); // Uncaught ReferenceError: x is not defined
console.log(y); // 2
펑션 스코프
자바스크립트 함수 안에서 선언된 변수는 해당 함수의 지역 변수다.
지역 변수는 펑션 스코프를 갖는다.
즉, 해당 함수 안에서만 접근할 수 있다.
지역 변수는 함수가 시작할 때 생성되었다가 함수가 완료되면 지워진다.
자바스크립트에서 함수는 클로저의 역할을 하며 스코프를 형성한다. 그래서 함수 안에서 정의된 변수는 해당 함수 바깥이나 다른 함수에서는 접근할 수 없다.
글로벌 스코프
변수가 최외곽 함수 바깥에서 정의되면 전역 변수가 된다.
전역 변수는 글로벌 스코프를 갖고 프로그램 어디서든 접근할 수 있다.
아직 선언되지 않은 변수를 자동으로 글로벌 변수가 된다. (단, Strict Mode에서는 예외다.)
HTML에서 글로벌 스코프는 윈도우 객체와 같다.
var 키워드로 정의된 변수는 윈도우 객체에 속한다.
전역 변수인데 let 키워드로 정의된 것은 윈도우 객체에 속하지 않는다.
호이스팅
호이스팅이란 코드 실행 전에 모든 변수와 함수 선언을 스코프의 맨위로 끌어올리는 것이다.
초기화는 호이스팅하지 않고 선언만 호이스팅되기 때문에 아래 코드에서 undefined가 나온다.
자바스크립트는 코드 실행 전에 변수 x를 메모리에 할당한다.
console.log(x) // undefined
var x = 100;
위 코드를 자바스크립트는 아래와 같이 해석한다.
var x;
console.log(x);
x = 100;
만약 var 키워드 없이 선언 없이 값을 초기화하기만 하면 ReferenceError가 생긴다.
console.log(x);
x = 100; // ReferenceError: x is not defined
호이스팅으로 인해 예상치 못한 결과가 생길 수 있다.
아래 코드의 hoist 함수 내에서 x는 호이스트되고 if문이 실행되지 않기 때문에 x에는 값이 할당되지 않고 undefined가 나온다.
이러한 특성이 버그를 만들어낼 수 있다.
var x = 100;
function hoist() {
if (false) {
var x = 200;
}
console.log(x);
}
hoist(); // undefined
반면에 let과 const는 블락 스코프이기 때문에 호이스트되지 않는다.
아래 코드에서 if문은 실행되지 않으며 지역변수 x도 호이스팅되지 않는다.
그러므로 x는 전역변수를 참조하여 true를 반환한다.
let x = true;
function hoist() {
if (false) {
let x = false;
}
console.log(x);
}
hoist(); // true
결론적으로 var는 호이스팅 특성으로 프로그램 상에서 에러 없이 undefined를 반환할 수 있어서 사용을 지양하도록 하자. 반면에 let과 const는 선언하기 전에 변수를 사용하려고 하거나, 재선언을 하려고 하면 에러를 던지기 때문에 버그를 사전에 방지할 수 있다.
var, let, const 비교
자바스크립트는 변수를 선언할 때 var, let, const 세 가지 키워드를 사용한다.
스코프와 호이스팅 관점에서 var, let, const를 비교할 수 있다.
var, let, const는 스코프, 호이스팅, 재할당, 재선언에서 차이가 있는데 이를 정리하면 아래와 같다.
키워드 | 스코프 | 호이스팅 | 재할당 가능 여부 | 재선언 가능 여부 |
var | 함수 | O | O | O |
let | 블락 | X | O | X |
const | 블락 | X | X | X |
const는 재할당이 불가하기 때문에 상수를 정의할 때 const 키워드를 사용한다.
상수 변수명은 대문자로 작성하는 것이 관례다.
프로그래밍에서 값이 바뀔 수 없는 것을 immutable하다고 하고, 값이 바뀔 수 있는 것일 mutable하다고 한다.
그런데 const는 재할당이 안되긴 하지만 mutable하다. const로 정의된 객체의 속성을 수정할 수 있기 때문이다.
const CAR = {
color: "blue",
}
CAR.color = "red";
console.log(CAR); // {color: "red"}