JavaScript

#20 자바스크립트(JavaScript) - 호이스팅(Hoisting)

에이블디 2022. 4. 15. 22:36

안녕하세요 여러분! 에이블디 입니다!

 

이번 시간에는 호이스팅(hoisting)에 대해 알아보려 해요!

 

지난 시간에 함수에 대해 알아볼 때 자바스크립트는 소스코드를 한 줄씩 순차적으로 실행하기 전에 모든 선언문을 찾아내어 먼저 실행한다고 설명한 것 기억나시나요?

 

변수, 함수 등을 선언할 때 사용하는 var, let, const, function, function*, class를 사용하여 선언한 모든 식별자는 다른 코드보다 먼저 실행되는 특징을 가지고 있는데, 이를  호이스팅이라고 합니다.

 

이 호이스팅을 이해하기 위해 다시 한번 자바스크립트의 특징에 대해 짚고 넘어가 볼게요!

 

간단하게 변수 하나를 선언해 볼게요!

var number = 1;

지금부터 변수에 대해 조금 더 이해하는 시간을 가지고 가보도록 할게요!

변수는 어떠한 값을 저장하기 위해 확보한 메모리 공간이고, 그 메모리 공간을 식별하기 위해 이름도 붙여주었던 것 다들 기억하시죠?

여기서 선언된 변수의 변수명(변수의 이름) 'number'는 변수의 값이 아닌 메모리의 주소를 기억하고 있습니다.

그래서 변수명을 '식별자'라고도 해요!

var number = 1;

console.log(number);

그리고 위의 코드처럼 변수명을 사용하면, 자바스크립트 엔진이 변수명과 연결된 메모리 주소를 통해 거기에 저장된 값 1을 반환하게 되는 원리로 자바스크립트는 동작하게 됩니다.

 

변수의 선언은 지금까지 var로 해왔었는데요, ES6에서 letconst가 추가가 되었어요!

let과 const에 대해서 제대로 이해를 하려면 호이스팅스코프의 개념을 이해하셔야 하는데요, 이번 시간에 호이스팅에 대해 이해하고, 다음 시간에는 스코프에 대해 이해를 한 뒤에 let과 const에 대해 풀어드릴게요!

 

다시 돌아와서! 자바스크립트에서 변수 선언은 선언 단계와 초기화 단계를 거치게 되는데요, 여기서 선언 단계변수명을 통해 자바스크립트 엔진에 변수의 존재를 알리는 단계이고, 초기화 단계값을 저장하기 위한 메모리 공간을 확보하고 변수에 undefined를 할당해 초기화하는 과정을 말합니다.

 

여기서 변수 number를 값을 할당하지 않고 선언만 해볼게요.

var number;

console.log(number);

var를 사용한 변수 선언은 선언 단계와 초기화 단계가 동시에 진행되어 변수 number에 undefined를 할당해 초기화를 해줍니다.

콘솔로 변수 number를 출력해 볼까요?

 

 

undefined가 출력되는 것을 확인할 수 있네요!

 

여기서 지난 시간에 함수에 대해 배울 때 console을 함수의 선언부 보다 먼저 작성했던 것처럼 이번에도 변수의 선언 부보다 먼저 console로 변수를 호출해 보도록 하겠습니다.

console.log(number);

var number;

과연 변수를 선언한 선언문을 먼저 찾아 실행하고 number를 출력하는지 코드를 실행시켜 볼게요!

 

 

변수의 선언 단계와 초기화 단계를 먼저 거쳐 변수 선언이 먼저 이루어져 console로 number 변수를 호출했을 때 undefined를 출력하는 걸 확인할 수 있네요!

호이스팅이 된 걸 확인할 수 있습니다!

 

지금부터 조금 더 깊이 들어가 볼게요! 잘 따라와 주세요!

 

변수에 값을 할당할 때에는 할당 연산자(=)를 사용한다는 건 지난 시간에 다루어서 잘 알고 계시죠?

var number = 1;

바로 위의 코드처럼 말이죠!

여기서 변수 선언과 변수에 값을 할당하는 것은 하나의 문(statement)으로 표현할 수 있지만, 선언과 할당은 실행 시점이 다릅니다.

코드를 순차적으로 실행되는 시점을 런타임이라고 하는데요,

변수 선언은 호이스팅이 되어 런타임 이전에 실행이 되지만, 값의 할당은 런타임 때 실행됩니다.

 

더 빠른 이해를 위해 선언과 할당의 시점을 한눈에 보기 위해 코드를 실행시켜 이해해 보도록 할게요!

console.log(number);

var number = 1;

console.log(number);

console을 변수를 선언하고 값을 할당하는 코드의 위아래에 작성하고 number변수를 호출하는 코드인데요, 결과가 어떻게 나오는지 실행시켜보도록 하겠습니다!

 

 

첫 번째 console 코드에서는 number 변수를 호출했을 때 호이스팅으로 인해 변수의 선언과 초기화 단계만 먼저 이루어져 있는 상태이기 때문에 undefined를 출력하는 걸 볼 수 있네요.

두 번째 console 코드에서는 number 변수를 호출했을 때 호이스팅으로 변수의 선언과 초기화 단계 이루어진 이후에 값 1을 할당받아 1이 출력되는 것을 확인할 수 있습니다.

 

함수에서의 호이스팅은 좀 특별한데요, 익명 함수를 사용할 때 변수에 함수를 바로 선언해서 사용했던 것 기억하시나요?

function sum(a, b) {
    return a + b;
}

var sum = function(a, b) {
    return a + b;
}

위에 작성한 두 코드의 차이가 보이시나요?

첫 번째 코드는 sum이라는 함수 명을 사용해 선언 한 일반적인 함수의 선언식이고 두 번째 코드는 sum이라는 변수에 익명 함수를 선언한 것인데요, 두 가지 타입의 함수가 어떻게 호이스팅이 되는지 살펴보도록 할게요!

 

이번엔 객체의 속성을 나타내 주는 console.dir()을 사용해서 살펴보도록 하겠습니다.

console.dir(sum);

function sum(a, b) {
    return a + b;
}

 

[function: sum]이라는 결괏값을 출력하네요!

이건 함수 자체를 호이스팅 시켰다는 의미입니다.

그래서 함수 선언 이전에 인수값을 넣어 함수를 실행시켜도 정상적으로 실행이 가능한 상태가 된 것이지요.

한번 확인해 볼까요?

console.dir(sum);
console.log(sum(1, 2));

function sum(a, b) {
    return a + b;
}

 

함수 선언 이전에 함수를 실행시켰는데도 인수 1과 2를 받아 1 + 2를 실행하여 3이라는 결괏값을 출력한 걸 확인할 수 있습니다.

 

그럼 두 번째 변수에 익명 함수를 작성하여 바로 값을 할당받게 한 경우에는 어떤 결괏값을 출력하는지 살펴볼까요?

위와 마찬가지로 먼저 console.dir()을 사용하여 객체의 속성부터 확인해 보도록 하겠습니다.

console.dir(sum);

var sum = function (a, b) {
    return a + b;
}

 

이번엔 일반적으로 선언한 함수와는 다르게 앞서 보았던 변수에 적용되었던 호이스팅과 같이 런타임 이전에 변수 값을 undefined로 초기화만 시킨 상태이네요?

이처럼 변수에 익명 함수를 작성하여 바로 결괏값을 할당받게 작성한 경우에는 호이스팅이 변수와 같이 동작하여 익명 함수는 런타임 이후에 동작하여 결괏값을 할당받을 수 있게 동작합니다.

 

어떻게 동작하는지 직접 확인해 봐야겠죠?

console.dir(sum);
console.log(sum(1, 2));

var sum = function (a, b) {
    return a + b;
}

 

익명 함수를 쓸 수 없는 상태이기 때문에 에러를 뿜는 것을 확인할 수 있습니다.

그럼 이번엔 런타임 이후에 제대로 동작하는지 확인해 볼게요!

console.dir(sum);

var sum = function (a, b) {
    return a + b;
}

console.log(sum(1, 2));

런타임 이후에 정삭적으로 동작하여 3이라는 결괏값을 출력하는 걸 확인할 수 있습니다!

 

이제 호이스팅에 대해 어느정도 감이 잡히시나요?

어느정도 감이 잡히실 때까지 코드를 직접 작성해 보시고 바꿔도 보시고 이것저것 많이 연습하셔서 꼭 이해하셨으면 좋겠습니다!

 

이번 시간에는 호이스팅에 대해 알아보았습니다.

다음 시간에는 스코프에 대해 알아볼게요! 여러분 다음 시간에 만나요!