코드에 선언된 변수 및 함수가 코드 상단으로 끌어올려지는 것처럼 동작하는 것을 말합니다.
이는 자바스크립트 파서가 내부적으로 끌어올려서 처리하는 것으로, 실제 메모리에서는 변화가 없습니다!
이러한 호이스팅이 발생하는 이유는 자바스크립트 해석기의 동작 방식 때문입니다.
자바스크립트 코드가 실행되면 파싱을 하게 되는데, 이때 코드를 해석해 전역 컨텍스트에 전역 변수 및 함수를 등록하려하기 때문에 끌어올려지는 현상이 발생하게 됩니다.
console.log(name); // undefined
var name = 'jeongmin';
코드 상으로 보기에는 name
변수의 생성과 초기화가 console.log
이후에 이루어졌으니 에러가 발생할 것 같아 보이지만, undefined
로 출력되는 것을 볼 수 있습니다.
위 코드는 아래와 같은 의미를 가집니다.
var name = undefined;
console.log(name); // undefined
name = 'jeongmin';
이러한 현상이 호이스팅으로, 해당 변수가 상단으로 끌어올려져 undefined
로 초기값이 할당되는 것입니다.
따라서 변수가 선언되기 전에 변수를 사용할 수도 있습니다.
name = 'jeongmin';
var name;
스코프와 함께 예시를 보도록 합니다.
var는 함수 스코프를 가지므로 즉시 실행함수와 함께 코드를 작성해보겠습니다.
var x = 'outer';
(function() {
console.log(x); // undefined
var x = 'inner';
}());
먼저 초기화된 outer가 출력될 것 같지만, undefined가 출력됩니다.
var x가 해당 스코프의 최상단으로 호이스팅되기 때문입니다.
위 코드는 아래와 같은 의미를 가집니다.
var x = 'outer';
(function() {
var x;
console.log(x); // undefined
x = 'inner';
}());
함수의 경우에는 표현식이냐 선언식이냐에 따라 조금 다르게 동작합니다.
var result = sum(1 , 1); // error!
var sum = function(num1, num2){
return console.log(num1 + num2);
}
위와 같은 표현식의 경우 var sum
에undefined
가 초기값으로 할당되기 때문에 sum is not a function
이라는 에러 문구가 뜨게 됩니다.
var result = sum(1, 1); // 2
function sum(num1, num2){
return console.log(num1+num2);
}
위와 같은 선언식의 경우 함수가 그대로 끌어올려지기 때문에 sum 로직이 잘 실행됩니다.
console.log(name); // reference error!
const name = 'danmin';
위의 코드는 var
와 달리 에러를 발생시킵니다.
이러한 결과는 let/const 선언이 호이스팅을 수행하지 않는 것처럼 보이는데, 그렇지 않습니다.
위의 스코프 예시와 함께 보도록 하겠습니다.
const x = 'outer';
(function() {
console.log(x); // reference error!
const x = 'inner';
}());
만약에 호이스팅이 일어나지 않는 것이라면 최상위 스코프의 outer
가 출력되어야 하지만, 에러가 발생하게 됩니다.
즉, 참조 에러가 발생하는 것 자체가 호이스팅이 되기 때문입니다.
초기화 전에 접근할 경우 var
는 undefined
를 반환하지만, let/const
는 에러가 발생하게 됩니다.
그렇다면 왜 이러한 에러가 발생하는 것일까요?
바로 Temporal Dead Zone
의 영향을 받기 때문입니다.
자바스크립트는 대부분의 언어와 같이 lexical scope
를 따르는데, lexical 환경에 포함될 때 변수가 생성되지만 실행되기 전까지는 접근을 막는 개념으로 볼 수 있습니다.
즉, 새로운 범위에 진입할 때마다 지정된 범위에 속한 모든 let/const
바인딩이, 지정된 범위 내부의 코드가 실행되기 전에 일어나게 되는데, (호이스팅)
바인딩이 일어나기 전까지 접근을 막는 것입니다.
이 때
let
의 경우 lexical 바인딩 시 초기화 구문이 없으면undefined
가 할당됩니다.
const
는 반드시 선언과 동시에 할당을 해주어야 합니다.
디폴트 파라미터에서도 TDZ
가 적용됩니다.
(function(a, b = a) {
console.log(a); // 1
console.log(b); // 1
}(1, undefined));
디폴트 파라미터는 왼쪽에서 오른쪽으로 실행되기 때문에, b
의 초기화 구문이 a
를 읽을 수 있기 때문에 정상적으로 작동합니다.
(function(a = b, b) { // ReferenceError
/* ... */
}(undefined, 1));
a
의 초기화 구문이 b
를 읽을 때 b가 TDZ에 있으므로 참조에러가 발생하게 됩니다.
클래스에서도 TDZ
가 적용됩니다.
class Person {
constructor(age, nickname) {
this.name = 'gildong';
this.age = age;
this.nickname = nickname;
}
}
class Error extends Person {
constructor(age, nickname) {
this.age; // reference error!
}
}
class Success extends Person {
constructor(age, nickname) {
super(age, nickname);
this.name = 'jeongmin';
}
}
const danmin_1 = new Error(23, 'danmin');
const danmin_2 = new Success(23, 'danmin');
상위 생성자를 호출하기 전에 this
에 엑세스하려고 하는 하위 클래스의 생성자는 참조에러를 발생시키 됩니다.
하위 클래스의 constructor
내부에서 super()
를 호출해야 this
에 접근할 수 있게 됩니다.
TDZ
는 초기화되지 않은 바인딩에 엑세스할 경우 에러를 발생시키기 때문에 유용합니다.
var
의 경우 TDZ
가 적용되지도 않을 뿐더러 함수레벨 스코프를 가지기 때문에 디버깅과 가독성이 좋지 않다는 단점이 있습니다.
따라서 let/const
로 통일성 있게 코드를 작성하면 좋을 것 같습니다 :)
Their gorgeous companions will make all your secret dreams come true. Enjoy a thrilling rendezvous with a striking brunette or an alluring blonde. Pakistani Delhi Escort Their elite escorts are highly educated, well-traveled, and speak fluent English so you can indulge in flirtatious conversation before getting down to business. Safemeetup’s top priority is your complete satisfaction and confidentiality. Forget your inhibitions and enjoy a romantic interlude you’ll never forget!