211120 - 호이스팅

빡새·2025년 3월 2일

https://m.blog.naver.com/tcloe8/221549773024

hoist
1. 동사 (흔히 밧줄이나 장비를 이용하여) 들어[끌어]올리다
2. 명사 (화물장애인을 들어올리기 위한) 승강 장치

네이버 사전에서 hoist 라는 단어를 찾으면 아래와 같다.

//자바스크립트에서의 호이스트(Hoist)

개발자가 아래와 같은 코드를 작성했다고 치자.

if(true){
	var name = 'kim kimkim';
}
console.log(name);

변수는 일반적으로 블록 스코프{ } 안에서 유효하기 때문에 블록이 종료된 이후의 console.log에 name이 제대로 출력되지 않을 것이라 생각할 것이다. 하지만 콘솔에 kim kimkim이 출력되는 것을 확인 할 수 있다.

자바스크립트에서의 변수 호이스팅은 정의된 변수의 선언문을 유효 범위의 최상단으로 끌어올리는 것이다. 변수의 선언과 할당이 동시에 일어나지 않고 분리되는 것이다.

즉, 변수가 함수 내에서 정의된 경우 : 선언이 함수의 최상위로 호이스트 됨
변수가 함수 바깥에서 정의된 경우 : 선언이 전역 컨텍스트의 최상위로 호이스트 됨

호이스팅 된 변수의 경우 선언이 할당과 동시에 일어나는 것이 아니라, 선언부만 최산단으로 호이스트되어 가장 먼저 해석된다는 점이 중요하다.

//선언과 할당

선언은 변수를 초기화하는 구문을 말하고 할당은 변수에 값이 부여되는 것을 말한다.
호이스팅에 의해 이 두 가지가 분리될 수 있는데, 아래 코드로 확인해 보자.

  1. 변수 선언

아래 코드를 보면 data라는 변수는 아직 초기화되지 않았다.

function HoistD(){
	console.log(data);
	var data = 100;
	console.log(data);
}
HoistD();

다른 언어라면 초기화되지 않은 변수를 호출하니 오류가 날 것이다.
그런데 이 자바스크립트에서는 오류대신 undefined가 출력된다.
윗줄의 console.log 코드가 바로 아래에 있는 var data = 100; 에서 data를 hoist하기 때문이다.

변수가 function 안에서 정의된 경우
이 변수의 선언(여기서는 var data = 100;)이 함수의 최상단으로 이동되기 때문이다.

선언 : 자바스크립트 엔진 구동 시 최상단으로 호이스트 됨
할당 : 런타임 과정에서 이루어지기 때문에 호이스팅 되지 않음 (원래 위치에서 할당)

if(true){
var name = 'kim kimkim';
}
console.log(name);
//개발자가 작성한 코드

var name; //변수의 선언이 최상단으로 호이스트 됨. 할당은 따라오지 않음.
if(ture){
	var name = 'kim kimkim'; //앞에서 선언한 변수를 여기서 할당함.
}
console.log(name);
//변수의 선언이 호이스트 된 코드

1-1. var의 유효 범위(scope)

선언은 유효 범위의 최상단으로 호이스트 된다. 여기서 유효 범위는 정확히 어디까지일까?
변수 선언을 하는 var는 let이나 const와는 다른 유효 범위를 가지고 있다.

var는 function-scope이고 let과 const는 block-scope이다.
즉, var는 단순히 블록 {}이 이나라 함수 function 함수명(){} 안에서 유효하다.
var 변수는 function-scope이므로 function 내의 선언들은 유효 범위(function)의 최상단으로 호이스트 된다.

function varScope(){
	if(true){
		var name = 'kim';
	}
	console.log(name);
}


function varScope2(){
	for(var i=0; i<5; i++){
	//do something
	}
	console.log(i);
}

if(true){var score = 100;}
console.log(score);
//개발자가 작성한 코드
var score; //한 단계 높은 function이 없어서 스크립트 최상단으로 선언이 호이스트 됨

function varScope(){
	var name; //function 안에서 선언이 호이스트 됨
	if(true){
		name = 'kim'; //name에 값이 할당됨
	}
	console.log(name);
}

function varScope2(){
	var i; //function 안에서 선언이 호이스트 됨
	for(i=0; i<5; i++){ //i에 값이 할당됨
	//do something
	}

if(true){score = 100;} //score가 할당됨
console.log(score);
//호이스팅 된 코드

맨 마지막 if 구문은 function 밖에서 선언되었다.
이런 경우 global-scope가 적용되는데, global-scope도 function-scope처럼 작용하기 때문에 변수를 최상단으로 이동시킨다.
이 코드에서 선언된 변수는 전역 컨텐스트의 최상단으로 호이스트 되었다.
//내 주석 - global-scope도 하나의 function-scope로 본다는 이야기인 듯?

2. 함수 선언

함수 역시 호이스팅 된다.
함수의 선언 부분이 함수 실행 부분보다 뒤에 있더라도 자바스크립트 엔진이 호이스팅해 준다.
즉, 함수 선언 부분을 맨 위로 끌어올린 채로 해석한다.
단, 함수 선언만 끌어올릴 뿐, 변수 값은 끌어올리지 않는다.

다음 예제를 살펴보자.

sayHello(); //출력 hello
function sayHello(){
	console.log('hello');
}

sayHello() 함수가 선언되기 전에 함수 실행 코드가 먼저 쓰였다.
자바스크립트 엔진에서 sayHello() 함수의 선언 부분을 호이스팅하여 global 객체에 등록시키므로(global-scope) hello가 정상적으로 출력된다.

//오류가 발생하는 경우

아래 예제도 살펴보자.

sayHello(); //syntax Error
var sayHello = function(){ console.log("hello); }
//개발자가 쓴 코드
  • 선언 방식이 다르지만 이것도 함수를 선언한 것이다.
// 함수 선언식
function sayHello(){ 
	// do something 
} 

// 함수 표현식 등의 이름으로 부른다.
var sayHello = function(){ 
	//do something 
} 

var sayHello는 변수이기 때문에 에러가 발생한다.
선언과 할당이 분리되기 때문이다.
선언과 할당 중에 선언 부분만이 최상단으로 호이스트 되고 할당 부분은 그 자리에서 실행된다.

var sayHello;
sayHello();
sayHello = function(){ console.log("hello"); }
//호이스팅 된 코드

순서로 보면 sayHello의 선언이 이루어지고 바로 sayHello를 호출하지만 그 내용에는 함수고 뭐고 아무것도 없는 상태다.

//호이스팅 우선 순위

변수 및 함수 선언 시 선언 구문이 유효 범위의 최상단으로 호이스트 된다는 것을 배웠다.
그렇다면 변수 선언과 함수 선언의 우선 순위는 어떨까?
"변수 선언 먼저 -> 그 다음 함수 선언 호이스트" 순이다.
변수 선언이 더 높은 우선 순위를 가진다.

아래 코드에서 typeof의 결과값이 어떻게 변하는지 과정을 생각해 보자.

function myName(){
	console.log('hello');
}

function yourName(){
	console.log('everyone');
}

var myName = 'kim';
var yourName = 'bye';

console.log(typeof myName);
console.log(typeof yourName);
//개발자가 작성한 코드

typeof 의 결과가 어떻게 나올까?
호이스팅을 감안하여 typeof가 어떤 과정으로 변할지 생각해 보자.

var myName;
var yourName;

function myName(){
	console.log('hello');
}

function yourName(){
	console.log('everyone');
}

myName = 'kim';
yourName = 'bye';

console.log(typeof myName);
console.log(typeof yourName);
//호이스팅 된 코드

코드 결과를 확인해 보면 두 typeof 모두 'String'을 출력한다.
변수가 선언 -> 함수 선언 -> 마지막으로 값을 kim, bye로 할당했기 때문이다.

//https://www.youtube.com/watch?v=GprF-5Jro08

const test02 = (function(){ //do something })();
const test03 = function(){ //do something };
function test04() { //do something }
import { test05 } from './here';

아래 순서로 적용 범위가 넓다.
test02 -> test03 -> test04 -> test05

test02는 그 자리에서 한 번 실행하고 뒤에서 다시 쓸 수 없음.
그냥 어떤 값을 얻기 위한 로직 블록 정도 역할.
const 유효 범위는 블록 단위.
그 블록 바깥에까지 영향을 미치는 것을 방지함.
고려할 요소가 줄어드니까 뒤 이이서 코드 읽을 때 더 편해지겠지.

test03은 함수를 만들어서 어떤 변수에 넣어 놨으므로 다시 쓸 수 있음.
단, 그 아래로만 가능. 호이스팅 되더라도 선언 부분만 올라가고 할당 부분은 남아있기 때문.
const의 유효 범위, 같은 블록 내에서 자주 쓸 것 같은 함수라면 이렇게 선언해 놓고 아래에서 계속 부르면 좋지.

test04는 해당 자바스크립트 내에서 다 불러다 쓸 수 있음.
호이스팅 될 때 함수 자체를 끌고 옴. (단 변수값은 끌오오지 않음)

test05는 다른 자바스크립트에서 불러다 쓸 수 있음.

아래로 갈수록 영향력이 큼. 그만큼 여기저기서 불러다 쓰고 있을 가능성이 크므로 고치거나 할 때 주의해야겠지.

필요에 따라서 함수 선언 방식을 다르게 하는 게 좋은 코드가 되겠지.

0개의 댓글