호이스팅(hoisting)_var의 문제점

Lemon·2022년 3월 25일
1

JavaScript

목록 보기
3/17
post-thumbnail

호이스팅에 대한 정의를 알기 전에 var에 대해 먼저 알아야합니다.

var이란?

초기 자바스크립트 변수 선언 방식입니다. 2015년도에 자바스크립트가 ES6로 업그레이드 되면서 letconst가 나왔습니다. ES6 이후에는 잘 사용하지 않지만 오래된 자바스크립트에서 종종 볼 수 있습니다. 그렇다면 최근에 사용되지 않는 이유는 무엇일까요?


var의 문제점

1. 한번 선언된 변수를 다시 선언할 수 있습니다.

var name = "lemon";
console.log(name); // "lemon"
var name = "Mike";
console.log(name); // "Mike"

변수는 주민등록번호 같은것이기 때문에 다시 선언할 수 없어야합니다.
하지만 var은 변수를 다시 선언해도 아무런 에러가 뜨지 않습니다.
위의 코드를 let으로 바꿔서 똑같이 작성해보면

let name = "lemon";
console.log(name);
let name = "Mike";
console.log(name);

name은 이미 선언됐다는 에러 페이지가 뜹니다. 이게 정상적인 로직입니다.

2. 호이스팅

console.log(name); // undefined ⚠️원래는 에러가 떠야합니다.
var name = "Mike";
console.log(name); // "Mike"

자바스크립트는 인터프리터(코드를 한 줄씩 읽어 내려가며 실행하는 프로그램)언어 이기 때문에 코드를 항상 아래에서 위로 읽습니다. 1번째줄 입장에서 두번째 줄을 아직 안갔으니 name은 없는 변수여야 합니다. name이 선언되기 전에 찾게 되면 ReferenceError(참조에러 : 초기화 전에 name에 접근할 수 없음)가 나와야합니다.

위의 예제를 let 으로 바꾼다면 정상적으로 에러가 발생합니다.

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

var이 이런 말이 안되는 로직이 가능한 이유는 호이스팅(hoisting)이라는 개념 때문입니다. 선언된 변수들이 코드상 실제로 이동하진 않지만 최상위로 끌어올려진 것처럼 동작하는 것을 호이스팅이라고 합니다.

👇🏻 위의 예제를 호이스팅의 개념으로 정리해서 보자면 이렇습니다.

var name; → 선언된 변수가 최상위로 올라왔다.
console.log(name); // undefined
name = "Mike"; → 그러나 값은 올라가지 못한다. 따라서 값은 할당해주어야 한다.
console.log(name); // Mike 

함수가 실행되기 전에 선언된 변수와 함수를 가져가서 메모리에 기억해둡니다. 이게 무슨 뜻이냐면 자바스크립트가 실행될 때 어떤 변수랑 함수가 있는지부터 싹 훑어서 기억해두고 후에 누군가 name라는 변수를 부르면 자바스크립트가 기억해둔 변수랑 함수에서 찾아주는 것을 말합니다. 그렇지만 변수 할당된 값은 찾지 못해서 undefined가 나오는 걸 볼 수 있습니다.

📍undefined 가 나타나는 이유

var로 선언한 변수의 경우 호이스팅 시 변수의 값을 undefined로 초기화합니다. 변수를 선언하기 전에 사용할 수 있지만 값은 나오지 않는 이유입니다.

✍🏻 호이스팅을 설명할 땐 주로 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는" 것으로 말하곤 합니다.

🤔const와 let도 호이스팅을 합니다. 근데 왜 에러가 나올까요?

Temporal Death Zon(TDZ)라는 것을 만들었기 때문입니다.

TDZ 영역에 있는 변수들은 사용할 수 없습니다. letconstTDZ의 영향을 받습니다. 일시적으로 죽은 공간이다라는 뜻입니다.

값을 할당하기 전에는 사용할 수 없도록 죽은 공간으로 만드는 것입니다. TDZ로 잠재적인 버그를 줄일 수 있습니다.

🖥️ “ name이 호이스팅으로 기억 되긴했지만 name선언문이 나오기 전까진 접근할 수 없어! 여기는 일시적으로 죽은 zone이야! ”

📍let의 호이스팅

호이스팅은 함수 내부에서도 일어납니다. 스코프 단위로 일어나기 때문입니다.

let age = 28;

function showAge() { 
	console.log(age); ⇒ Temporal Death Zon
	let age = 20; // ReferenceError
}

showAge();

3. 전역변수 / 지역변수 의 개념이 확실치가 않다.

전역변수는 블락 { } 밖에서 선언을 한 변수로 어디서든 쓰일 수 있습니다.
지역변수는 블락 { } 안에서 선언된 변수로 블락 안에서만 쓸 수 있습니다.

📍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
}

📍var = 함수 스코프(function-scoped)

var은 함수(function)안에서 쓴것만 지역변수로 올려두고, 나머지 for문, if문 등등에서 쓰인것은 다 전역변수로 사용합니다.

👇🏻 유일하게 벗어날 수 없는 스코프가 함수(function)입니다.

function add(num1, num2){
	var result = num1 + num2;
}

add(2,3);
console.log(result); // Uncaught SyntaxError 에러 발생

👇🏻 if문 안에서 var로 선언된 변수는 if문 밖에서도 사용이 가능합니다.

const age = 30;

if(age<19){
	var txt = '성인';
}

console.log(txt); // '성인'

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

console.log(i) // 1 2 3 4 5

👇🏻 let으로 바꾼다면?

for(let i = 1; i<5; i++){
	console.log(i)
}

console.log(i)

i는 선언되지않았다는 에러메세지가 나타납니다.



✍🏻최종 정리

  • var은 초기 자바스크립트 변수 선언 방식입니다.
  • var의 문제점
    1. 한번 선언된 변수를 다시 선언할 수 있습니다.
    2. 호이스팅으로 인해 선언 전의 변수를 사용할 수 있습니다.
    3. 전역변수 / 지역변수 의 개념이 확실하지 않습니다.
      constlet블록 스코프(block-scoped)입니다.
      var함수 스코프(function-scoped)입니다.
      var 함수를 제외하고는 스코프를 벗어나서도 변수를 사용할 수 있습니다.
  • constlet도 호이스팅을 하지만 Temporal Death Zon(TDZ)이 있어서 선언 전의 변수를 사용할 수 없습니다.
profile
프론트엔드 개발자 가보자고~!!

0개의 댓글