html, css, javascript를 독학으로 공부하다보니 어쩔 수 없이 제작된 지 오래된 컨텐츠를 통한 학습의 빈도가 잦을 수 밖에 없었다. 그래서 그런지 내게 변수선언은 var인데 무슨일인지 최신 컨텐츠에는 죄다 let을 쓰고 있는 것을 볼 수 있었다. 그래서 뒤쳐질 수 없으니 잽싸게 알아봤다.
Hoist는 '들어올리다'라는 뜻을 지니는데, JavaScript 내에서 호이스팅은 함수가 실행되기 전 변수들을 싹 훑어 최상단으로 들어올려 미리 기억하고 가는 것이다. 이게 무슨 말인가 싶을 수도 있으니 예시를 통해 알아보자.
var a = 1;
var name = "donghyun";
var age = 28;
console.log(age)
출력값:
28
이것이 일반적인 JavaScript 코딩으로 아무 이상이 없는 완전무결한 코딩이다.
그리고 console.log(age)는 문제없이 28의 값을 출력할 것이다.
console.log(a)
var a = 1;
console.log(a)
출력값:
undefined
1
이건 어떠한가? 첫번째줄은 변수가 선언되기 전이기 때문에 에러값을 출력하는 것이 당연하다.
하지만 너무도 인자한 JavaScript는 에러를 내기는 커녕 'undefined'로 초기화를 해버린다.
왜 그럴까? 여기서 호이스팅이 발현된다. 이미 JavaScript 엔진은 실행 전 한번 훑었기때문에 a = 1이라는 것을 기억하고있다. 그래서 에러를 내기보다는 이미 알고있는데 지금은 변수 선언 전이니깐 알아도 모른척하며 인심쓰는 꼴인 것이다. 이게 왜 문제가 되는 것이냐
console.log(a)
a = 1
var a
console.log(a)
출력값:
undefined
1
이 말도 안되는 코딩에 대해 에러를 띄우지 않고 역시나 undefined를 출력한 후 네번째 줄에 대한 값인 1을 출력한다. 인심좋은 JavaScript라서 그렇지 다른 언어한테는 짤없이 에러로 두들겨 맞는다. 다른 말로 문제가 있는 것이다.
또 다른 문제로는 전역변수와 지역변수를 구분하지 못한다는 것이다. 전역변수는 {}과 같은 블락 밖에서 선언되는 변수로 어디서든 쓰일 수 있는 변수를 일컫고, 지역변수는 if,for 등 블락 내에서 선언되어 다른 곳에서는 쓰일 수 없는 변수이다.
for(var i = 1; i < 5 ; i++){
console.log(i)
}
console.log(i)
출력값:
1
2
3
4
5
아무렇지 않게 5가 출력되는 것을 볼 수 있다. 함수 내에 위치한 지역변수만을 인식할 수 있고, 나머지 변수는 싸그리 다 전역변수로 호이스팅해버린다.
var a = 1
console.log(a)
var a = 2
console.log(a)
출력값:
1
2
변수 간에는 중복이 허용되지 않지만, 이 역시도 허용하고 만다.
그래서 JavaScript 개발자들은 이에 대한 문제점을 인식하고 let이라는 변수선언을 만들게 된다.
let은 이전에 var가 저지른 과오를 처리하고자 나왔기에 짤없이 error값을 출력한다.
console.log(a)
let a = 1;
console.log(a)
출력값:
Uncaught ReferenceError: a is not defined
at <anonymous>:1:13
정의되지 않았다고 똑바로 일러주고,
console.log(a)
a = 1
let a
console.log(a)
출력값:
VM208:1 Uncaught ReferenceError: a is not defined
at <anonymous>:1:13
이 역시 정의되지 않았다고 똑바로 일러준다.
그렇다고 let이 호이스팅을 하지않는다는 것은 아니다.
다만 변수가 정의되기 전 출력을 요하면 TDZ(Temporal Death Zone)으로 취급하여 a가 변수 선언되기 전까지는 넌 a에 접근못함을 알린다. 즉, 접근금지처분을 내린다.
나머지 예시를 마저 보면,
for(let i = 1; i < 5 ; i++){
console.log(i)
}
console.log(i)
출력값:
1
2
3
4
instrument.ts:113 undefined
let a = 1
console.log(a)
let a = 2
console.log(a)
출력값:
Uncaught SyntaxError: Identifier 'a' has already been declared
a가 이미 정의됐다고 일러준다.
이처럼 let 또한 호이스팅을 하지만 출력에 있어서는 엄격한 기준을 가지고 있다.
var의 오류를 해결하고자 등장했지만, 이는 그냥 var쓰지말고 let만 쓰라는 것이니
앞으로 let만 쓰도록 하자!