JavaScript Hoisting

정현수·2021년 8월 17일
0

지식정리

목록 보기
3/5
post-thumbnail

📌 hoist의 사전적 의미

hoist는 감아올리기
hoisting은 감아올리기, 감아올림 그런 의미인데
자바스크립트 호이스팅이니까 자바스크립트에서 무언가를 감아올린다 라는 의미가 되겠다.

정확히는 자바스크립트가 실행될 때 자바스크립트 Parser가 어떻게 자바스크립트 코드를 처리하는지에 대한 내용이다.

📌 그래서 어떻게 처리하는데?

코드에서 변수, 함수의 "선언"들을 위로 올려서 처리한다.

중요

  1. 변수, 함수의 선언들을 물리적으로(실제 코드)에서 감아올리지 않고,
    Parser가 위로 올려서 처리한다는 것
  2. 위에서 계속 강조하고 있지만 변수, 함수의 할당이 아닌 선언을 올려서 처리하는 것이다.

변수 예시

var one = 1;
console.log(one, two); // two is not defined

위의 예시에는 two 가 선언되어 있지 않으므로 당연히 에러가 뜬다.

var one = 1;
console.log(one, two); // 1 undefined
var two;

위의 예시에서도 코드 순서대로라면 two 를 선언하기 이전에 호출했으므로 에러가 나야하지만,

Javscript hoisting이 작동해 two 의 선언을 우선적으로 실행했다. 그렇기 때문에 에러가 아닌 undefined가 뜨는 것을 볼 수 있다.

var one = 1;
// 1 undefined 👌
// 1 2 ❌
console.log(one, two); 

var two = 2;

위의 hoisting을 봤다면 오해할 수 있는 부분이 있다.
위의 예시를 보면 콘솔에 one, two를 띄우는데

아! JavaScript hoisting으로 two를 먼저 선언하니까 1 2 라고 나오지 않을까?

라고 생각할 수 있지만, 그건 변수의 할당과 선언을 헷갈린 것이다.

hoisting은 변수의 선언만을 책임지기 때문에 위의 예시에서 볼 수 있듯 1 undefined가 뜬다.

함수 예시

함수중에서도 함수 표현식hoisting이 안되고, 함수 선언문hoisting이 일어난다.

함수 선언문

우리가 자주보는 함수 선언과 동일한 방법

// Hoisting 👌

function test1() {
	// 구현 
}

함수 선언문은 어디에 선언이 되었든 hoisting이 일어난다.

// 함수안에서도 똑같이 hoisting이 일어난다는 것을 보여줌

/* hoisting 일어나기 전 */
function test() {
  var func1 = innerFunc();
  	
  // innerFunc
  console.log(func1);
  
  function innerFunc() {
     return 'innerFunc'; 
  }
}

test();
/* hoisting 일어난 후 */
function test() {
  // hoisting으로 선언 우선 호출
  var func1;
  
  // hoisting으로 우선 호출
  function innerFunc() {
    return 'innerFunc'; 
  }
  
  // 변수, 함수 "선언" 후에 할당
  func1 = innerFunc();
  
  // innerFunc
  console.log(func1);
}

test();

함수 표현식

함수를 변수에 할당 시켜놓은 것.
함수를 호출하는 것이 아님.

// Not hoisting ❌

// 익명 함수 표현식
var callFunc = function () {
 	// 구현 
}

// 기명 함수 표현식
var callFunc = function test1 () {
 	// 구현 
}

함수 표현식은 hoisting이 적용되지 않기 때문에 코드가 원하는대로
실행되지 않을 수 있다. (선언 오류가 날 수 있음)

/* hoisting 전 */
function test() {
  // undefined
  console.log(test1);
  
  //TypeError: innerFunc is not a function
  innerFunc();
  
  var test1 = innerFunc();
  
  var innerFunc = function() {
    return 'innerFunc'; 
  }
}

test();
/* hoisting 후 */
function test() {
  // hoisting으로 선언 우선 호출
  var test1;
  var innerFunc;
  // undefined
  console.log(test1);
  // TypeError: innerFunc is not a function
  innerFunc();
  
  test1 = innerFunc();
  
  // 함수 표현식은 hoisting이 일어나지 않는다.
  var innerFunc = function() {
    return 'innerFunc'; 
  }
}

test();

📌 hoisting 우선 순위

변수가 함수보다 우선 순위가 높음.
만약 같은 이름의 함수와 변수가 있다면, 변수의 값 할당에 따라 달라진다.

/* 변수가 우선 */
var result = 1;

function result() {
  return 'function';
}

// 1
console.log(one);
/* 함수가 우선 */
// 변수에 값이 할당 되어있지 않음
var result;

function result() {
  return 'function';
}

// function
console.log(one());

📌 var, let, const

var

위에서 계속 var 를 사용했다.
var 는 es6 이전 문법이다.

let, const

letconst 는 es6에 나온 새로운 문법이다.

차이점

// undefined => hoisting으로 선언이 우선적으로 일어남
console.log(val);
var val = 1;
// throws a ReferenceError
console.log(val);
let val = 1;

이렇게 var는 변수가 초기화 되기 전에 호출이 되면 undefined로 에러가 뜨지 않는다. 그래서 예측이 되게 어렵다.
하지만 letconst는 레퍼런스 오류가 뜨기 때문에 오류를 예측할 수 있게 된다. 이것이 장점이다.

위의 예시만 보면 letconsthoisting이 일어나지 않는 것 처럼 보인다. let / const 선언 변수는 호이스팅되지 않는 것이 아니다.

스코프에 진입할 때 변수가 만들어지고 TDZ(Temporal Dead Zone)가 생성되지만, 코드 실행이 변수가 실제 있는 위치에 도달할 때까지 액세스할 수 없는 것이다.

let / const변수가 선언된 시점에서 제어흐름은 TDZ를 떠난 상태가 되며, 변수를 사용할 수 있게 된다.

일시적 사각 지대 (Temporal Dead Zone; TDZ)

var 변수의 경우 선언 단계 - 초기화 가 동시에 이루어지는 반면, let / const 변수의 경우 선언 단계와 초기화 단계가 나누어서 이루어진다.

let / const 변수의 선언 단계와 초기화 단계 사이를 일시적 사각 지대 (Temporal Dead Zone; TDZ)라고 부른다.

실제 코드에서 let 변수의 선언 또는 const 변수의 선언 및 할당 (const 의 경우 선언과 동시에 값 할당이 되어야 한다.)이 나오기 전까지는 해당 변수는 TDZ에서 관리 한다고 생각하면 된다.

해당 코드가 나오기 전에 미리 사용을 하려고 할 경우 TDZ에서 ReferenceError를 발생 시킨다.

참고

https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html

https://medium.com/korbit-engineering/let%EA%B3%BC-const%EB%8A%94-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85-%EB%90%A0%EA%B9%8C-72fcf2fac365

profile
개인블로그를 만들었습니다. https://junghyeonsu.com/

0개의 댓글