호이스팅(Hoisting)

장윤희·2022년 6월 23일
0

JsPatterns

목록 보기
4/5
post-thumbnail

호이스팅(Hoisting)의 개념

함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다. (실제로 올려지는건 아님 그런것 같은 현상)

자바스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.

  • 함수 안에 존재하는 변수/함수선언에 대한 정보를 기억하고 있다가 실행시킨다.
  • 유효 범위: 함수 블록 {} 안에서 유효 (단순블록{}은 해당 안됨)

함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 끌어올리는 것이다.

  • 실제로 코드가 끌어올려지는 건 아니며, 자바스크립트 Parser 내부적으로 끌어올려서 처리하는 것이다.
  • 실제 메모리에서는 변화가 없다.

호이스팅의 대상

  • var 변수 선언함수선언문에서만 호이스팅이 일어난다.
  • var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
  • let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.
    (var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화 하지만 let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않는다.)
console.log("hello");
var myname = "HEEE"; // var 변수 
let myname2 = "HEEE2"; // let 변수 

/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 - 위와 동일 --- */
var myname; // [Hoisting] "선언"
console.log("hello");
myname = "HEEE"; // "할당"
let myname2 = "HEEE2"; // [Hoisting] 발생 X
foo();
foo2();
      
function foo() { // 함수선언문
	console.log("hello");
}
var foo2 = function() { // 함수표현식
	console.log("hello2");
}

var foo2; // [Hoisting] 함수표현식의 변수값 "선언"

function foo() { // [Hoisting] 함수선언문
	console.log("hello");
}
      
foo();
foo2(); // ERROR!! 
      
foo2 = function() { 
	console.log("hello2");
}

함수, 변수 우선순위

변수 '할당'이 함수 선언보다 우선 순위이고, 함수 선언이 변수 선언보다 우선 순위이다.
함수 선언문과 변수 할당문이 존재할경우, 변수 a선언 -> 함수 a선언 -> a에 값할당 순으로 실행된다.

var myName = "hi";

function myName() {
  console.log("yuddomack");
}
function yourName() {
  console.log("everyone");
}

var yourName = "bye";

console.log(typeof myName); //string
console.log(typeof yourName); //string

호이스팅이 일어나면 실질적으로 위와 같은 순서로 실행된다

함수선언문과 함수표현식에서의 호이스팅

함수선언문에서의 호이스팅

함수선언문은 코드를 구현한 위치와 관계없이 자바스크립트의 특징인 호이스팅에 따라 브라우저가 자바스크립트를 해석할 때 맨 위로 끌어 올려진다.

/* 정상 출력 */
function printName(firstname) { // 함수선언문 
	var result = inner(); // "선언 및 할당"
	console.log(typeof inner); // > "function"
	console.log("name is " + result); // > "name is inner value"
        
	function inner() { // 함수선언문 
		return "inner value";
	}
}
        
printName(); // 함수 호출 
/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 - 위와 동일 --- */
/* 정상 출력 */
function printName(firstname) { 
	var result; // [Hoisting] var 변수 "선언"

	function inner() { // [Hoisting] 함수선언문
		return "inner value";
	}

	result = inner(); // "할당"
	console.log(typeof inner); // > "function"
	console.log("name is " + result); // > "name is inner value"
}

printName(); 

함수선언문이 아래에 있어도 printName 함수 내에서 inner를 function으로 인식하기 때문에 오류가 발생하지 않는다.

함수표현식에서의 호이스팅

함수표현식은 함수선언문과 달리 선언과 호출 순서에 따라서 정상적으로 함수가 실행되지 않을 수 있다.
함수표현식에서는 선언과 할당의 분리가 발생한다.

1. 함수표현식의 선언이 호출보다 위에 있는 경우 - 정상 출력

 /* 정상 */
function printName(firstname) { // 함수선언문
	var inner = function() { // 함수표현식 
	return "inner value";
	}
                
	var result = inner(); // 함수 "호출"
	console.log("name is " + result);
	}

printName(); // > "name is inner value"
/* 정상 */
/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 - 위와 동일 --- */
function printName(firstname) { 
	var inner; // [Hoisting] 함수표현식의 변수값 "선언"
	var result; // [Hoisting] var 변수값 "선언"

	inner = function() { // 함수표현식 "할당"
		return "inner value";
	}
                
	result = inner(); // 함수 "호출"
	console.log("name is " + result);
}

printName(); // > "name is inner value"

2.함수표현식의 선언이 호출보다 아래에 있는 경우 (var 변수에 할당) - TypeError

/* 오류 */
function printName(firstname) { // 함수선언문
	console.log(inner); // > "undefined": 선언은 되어 있지만 값이 할당되어있지 않은 경우
	var result = inner(); // ERROR!!
	console.log("name is " + result);

	var inner = function() { // 함수표현식 
		return "inner value";
	}
}
printName(); // > TypeError: inner is not a function
/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 --- */
/* 오류 */
function printName(firstname) { 
	var inner; // [Hoisting] 함수표현식의 변수값 "선언"

	console.log(inner); // > "undefined"
	var result = inner(); // ERROR!!
	console.log("name is " + result);

	inner = function() { 
		return "inner value";
	}
}
printName(); // > TypeError: inner is not a function

Q. printName에서 “inner is not defined” 이라고 오류가 나오지 않고, “inner is not a function”이라는 TypeError가 나오는 이유?
A. printName이 실행되는 순간 (Hoisting에 의해) inner는 ‘undefined’으로 지정되기 때문
inner가 undefined라는 것은 즉, 아직은 함수로 인식이 되지 않고 있다는 것을 의미한다.

3. 함수표현식의 선언이 호출보다 아래에 있는 경우 (const/let 변수에 할당) - ReferenceError

 /* 오류 */
function printName(firstname) { // 함수선언문
	console.log(inner); // ERROR!!
	let result = inner();  
	console.log("name is " + result);

	let inner = function() { // 함수표현식 
		return "inner value";
	}
}
printName(); // > ReferenceError: inner is not defined

let/const의 경우, 호이스팅이 일어나지 않기 때문에 위의 예시 그대로 이해하면 된다.
console.log(inner);에서 inner에 대한 선언이 되어있지 않기 때문에 이때는 “inner is not defined” 오류가 발생한다.

호이스팅 사용 시 주의사항

  • 코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않도록 한다.
    → 함수 선언문보다 let / const를 이용한 함수 표현식을 쓰자.
  • var 변수는 호이스팅이 일어나 혼란스러운 코드가 될 수 있다. 되도록 쓰지 말자.

참고 자료
: https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html
: https://hanamon.kr/javascript-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85%EC%9D%B4%EB%9E%80-hoisting/

profile
멋쟁이

0개의 댓글