[Javascript] 호이스팅(Hoisting)과 var,let,const

김택수·2022년 2월 28일
0

호이스팅이란?

코드를 실행하기 전 변수 및 함수선언을 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상.

쉽게 설명할 때는, 변수나 함수의 선언이 최상단으로 끌어올려진 것. 이라고만 설명할 수 있지만 엄밀히 말한다면 끌어 올려진 것 같은 현상이 호이스팅이다.

끌어 올려진 것 같은 현상?

자바스크립트 엔진은 코드를 실행하기 전 실행 가능한 코드가 실행되기 위해 필요한 환경정보를 모아놓은 객체(실행 컨텍스트)를 생성하는 과정을 거치는데 이 과정에서 식별자(변수/함수명)들을 수집하여 메모리에 미리 저장해두기 때문에 위에서 아래로 코드가 실행되는 자바스크립트 구조 상 변수나 함수의 선언이 위로 끌어 올려진 것 같은 현상이 나타난다.

변수의 생성단계

1. 선언 단계(Declaration phase)

  • var a = 1을 선언했을 때, a가 선언되었다는 것만 알 수 있다.

2. 초기화 단계(Initialization phase)

  • a 변수에 값을 담기 위한 메모리가 할당되고 변수는 undefined로 초기화 된다.

3. 할당 단계(Assignment phase)

  • a 변수에 1이라는 값이 할당된다.

변수의 생성단계를 알아본 이유

자바스크립트에서는 var,let,const를 이용해 변수를 선언할 수 있는데, ES6 이후의 문법에서는 var 키워드의 사용을 지양한다. 그 이유가 바로 변수의 생성단계에서부터 var를 이용한 변수선언의 단점이 발견되기 때문이다.

var 키워드를 이용한 변수 선언의 단점

ES6 이전에는 변수를 선언할 때 var를 이용해 선언했다. 그러나 var를 이용한 변수선언에는 많은 단점들이 있다.

단점 1. 변수선언문의 이전에 변수를 참조하여도 에러를 띄우지 않는다.

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

해당 예시에서 에러를 띄울 것 같지만, var를 이용한 변수선언은 선언과 초기화를 동시에 수행하기 때문에 에러를 띄우지 않고 초기화 된 값인 undefined를 반환한다. 이는 코딩시 정확한 에러를 발견할 수 없고 개발자로 하여금 혼동을 야기할 수 있다.

단점 2. 지역변수와 전역변수의 경계가 정확하지 않다.

var a = 1 // 전역변수
function foo() {
 var b = 2 // 지역변수 
};
console.log(b) // 2

위의 예시에서 foo라는 함수 블록({})안에서 선언된 지역변수 b는 블록밖에서는 값을 참조할 수 없어야 한다. 그 이유는 아래의 예시와 같다.

for(var i = 1; i<5; i++) {
 console.log(i) // 1 2 3 4
}
console.log(i) // 5

for문 블록({})안에서 반복한 console.log(i)는 정상적으로 1 2 3 4 까지 반복하고 반복문이 종료되었다. 하지만 블록 밖에서 다시 console.log(i)를 했더니 5까지 값이 반복되었다. 이 이유는 var로 선언한 모든 변수는 전역/지역 가릴 것 없이 모두 호이스팅된다. 이런 경우는 개발자의 의도와 맞지않는 결과를 낳을 수 있다.

단점 3. 변수의 이름을 중복해서 재할당할 수 있다.

var a = 1;
console.log(a) // 1
var a = 2;
console.log(b) // 2

위의 예시처럼 var를 이용해 변수를 선언하면 같은 변수명에 계속 다른값을 할당할 수 있고, 에러를 띄우지 않는다. 이 경우의 문제는 바뀌지 않아야 할 값들이 어디선가 변경될 수 있기 때문에 좋지 못한 변수선언법이라고 할 수 있다.

var vs let

위와 같은 단점들 때문에 ES6부터 let을 이용한 변수 선언이 가능해졌다. let은 var의 단점을 보완하는데

보완점 1. 선언 및 초기화 단계가 분리되어 수행된다.

console.log(a) // Uncaught ReferenceError: a is not defined
let a = 1;

var의 단점 1과 같은 예시이지만 let으로 변수를 선언했을 때는 a가 정의되지 않았다는 에러를 띄운다. 이유는 선언만 되어있고 초기화(값의 할당)이 되지 않았기 때문이다. var는 초기화가 같이 이루어지면서 undefined라는 값을 할당하는 것과 같기 때문에 undefined를 띄우는 것이다. let을 이용한 변수선언은 초기화가 되는 문장을 만나기 전까지 변수를 참조할 수 없는데 이를 '일시적 사각지대(Temporal Dead Zone; TDZ)'라고 한다.

보완점 2. 지역변수와 전역변수의 경계가 명확하다.

for(let i = 1; i<5; i++) {
 console.log(i) // 1 2 3 4
}
console.log(i) // Uncaught ReferenceError: i is not defined

마찬가지로 var의 단점2와 같은 예시지만 let을 사용해 i를 선언하면 for문 밖에 있는 console.log에서는 i가 정의되지 않았다는 에러를 띄운다. 이유는 let 또한 호이스팅되는것은 맞지만 for문 안에서 정의된 i는 지역변수이기 때문에 호이스팅 되지 않았다. 그렇기 때문에 for문 밖에서는 i를 참조할 수 없다.

보완점 3. 변수에 재할당이 불가능하다.

let a = 1;
console.log(a) // 1
let a = 2;
console.log(b) // Uncaught SyntaxError: Identifier 'a' has already been declared

let으로 선언된 변수 a는 그 이후에 값을 재할당 할 수 없다. 위의 예시처럼 재할당 할 경우 구문에러를 띄우고 a는 이미 선언되었다는 에러명을 보여준다.

const를 이용한 변수선언

let과 같이 ES6 이후부터 const를 이용해 변수를 선언할 수 있다. 특징은 let과 같고 차이점은 let은 mutable(변경가능), const는 immutable(변경불가능)이다.

let name = "james";
console.log(name) // james
name = "john"
console.log(name) // john

const name = "james";
console.log(name) // james
name = "john"
console.log(name) // Uncaught TypeError: Assignment to constant variable.

위의 예시처럼 let으로 선언한 변수는 재할당이 가능하지만, const로 선언한 변수는 재할당이 불가능하다. 이는 비밀번호나 회원 ID같이 바뀌면 안되거나, 중복되면 안되는 정보들을 담기 위함이라고 생각하면 된다.

결론

  • 호이스팅은 변수 및 함수의 선언이 최상단에 끌어올려진 것 같은 현상을 말한다. (메모리에 변수를 미리 저장해두기 때문)
  • 변수는 선언-초기화-할당의 단계로 생성된다.
  • var를 이용한 변수선언에는 단점들이 존재한다.
  • ES6부터 var의 단점을 보완하기 위해 let과 const가 만들어졌다.
  • let과 const의 차이는 재할당의 가능여부이다.
  • var를 이용한 변수선언을 지양하자.

호이스팅을 공부하다보니 스코프와 실행 컨텍스트를 더 잘 알고 있어야 호이스팅 및 변수에 대한 내용을 더 잘 이해할 수 있을 것 같다. 자바스크립트의 중요한 구동원리라고 하니 필히 다시 공부해야겠다.

참고

Udemy - 혼자배우는 자바스크립트: 기본부터 포트폴리오까지 한번에 끝내기(Bitna Kim aka. 코딩하는 누나)

박동건님 벨로그 - var, let, const 차이점

하나몬님 블로그 - 호이스팅(Hoisting)이란?

profile
개발자 키우기 Lv1

1개의 댓글

comment-user-thumbnail
2022년 6월 25일

안녕하세요, 코드에 에러가 있는 거 같아 말씀드립니다. "단점 2. 지역변수와 전역변수의 경계가 정확하지 않다."의 예시로 있는 코드에서 console.log(b);에서 2가 나오지 않고 에러가 납니다. 확인 부탁드립니다 :)

답글 달기