기본적인 문법에 대해서 알고나니, 자연스럽게 원리가 궁금해져서 이것저것을 찾다 클로저(Closure)에 대해서 알게되었고, 또 자바스크립트에서 중요한 개념 중 하나라고 알고는 있어서 클로저에 대해서도 이것저것 영상을 찾아보고 했는데
클로저라는 개념을 제대로 이해하기 위해서는 선행되어야 하는 개념들이 있다는 걸 알게 되었습니다.
그래서 오늘부터 기본 개념인 호이스팅 부터, 스코프(Scope), 클로저(Closure), 실행컨텍스(Execution Context). 자바스크립트 이벤트 루프(Event loop)와 콜 스택(call stack) 등에 대해서 차례로 공부하고 정리해보고자 합니다.
호이스팅(Hoisting)
먼저 자바스크립트에서 호이스팅이란?
인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 임포트(import)의 선언문을 해당 범위의 맨 위로 끌어올리는 것처럼 보이는 현상을 뜻합니다
출처 : https://developer.mozilla.org/ko/docs/Glossary/Hoisting
호이스팅 - MDN Web Docs 용어 사전: 웹 용어 정의 | MDN
JavaScript 호이스팅은 인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 임포트(import)의 선언문을 해당 범위의 맨 위로 끌어올리는 것처럼 보이는 현상을 뜻합니다.
developer.mozilla.org
사실 설명만 봤을 때는 쉽게 이해가 가기 힘든데요, 코드를 예를 들어서 설명드리겠습니다.
먼저
var OTTService = "Netflix";
console.log(OTTService); // Netflix
라는 코드가 있습니다.
당연히 var OTTService 라는 변수를 콘솔로 출력해줄 경우 당연하게 해당 변수에 할당한 Netflix 가 출력됨을 예상할 수 있습니다.
하지만 이런 식으로 출력해보면 어떤 값이 출력될까요?
console.log(OTTService); // undefined
var OTTService = "Netflix";
console.log(OTTService); // Netflix
위의 콘솔은 OTTService 변수가 선언되기 전에 출력했기 때문에 에러가 출력될 것 같지만 정답으로는 undefined 가 출력됩니다.
이렇게 선언라인 전에도 에러가 나지 않고 변수를 참조하는 즉, 선언문이 마치 최상단에 끌러올려진 듯한 현상을 호이스팅(Hoisting) 이라고 합니다.
이 현상이 발생하는 이유는 선언문이 있는 코드라인 물리적으로 최상단에 끌러 올렸기 때문이 아니라 자바스크립트 엔진이 먼저 전체 코드를 스캔하면서 변수 같은 정보를 실행 컨텍스 어딘가에 미리 기록해두었기 때문입니다.
(참고) 이때 기록해두는 곳이 환경 레코드((Environment Record) : 식별자와 식별자에 바인딩된 값을 기록하는 객체) 이라고 합니다
이러한 호이스팅 현상을 두가지 종류로 나누어 설명드리겠습니다.
변수 호이스팅(Variable Hoisting)
변수 호이스팅 에서도 두가지로 나누어 설명드릴 수 있는데요.
바로 var 와 let, const 입니다.
먼저 var 변수에 대한 호이스팅 현상에 대해 설명드리고자 하는데요
console.log(OTTService); // undefined
var OTTService = "Netflix";
console.log(OTTService); // Netflix
먼저 아까 설명드린 코드를 다시 한번 살펴보겠습니다.
자바스립트 엔진은 코드를 실행하면 우선 전역 실행컨텍스트 한 칸을 생성해서 콜스택에 넣습니다.
그 후, 전체 코드를 스캔하면서 선언할 것(변수, 함수, 클래스 등)이 있는지 찾아보고 있다면 먼저 선언해둡니다.
선언하는 과정에서 실행해둔 실행 컨텍스트 안에 있는 환경레코드에 새로운 식별자 OTTService 를 기록합니다.
그리고 var 키워드의 경우는 undefined로 값을 초기화 해둡니다. { OTTService : undefined }
이렇게 본격적인 실행 단계에 앞서 스캔하고 준비하는 단계를 생성 단계라고 합니다.
실행컨텍스트를 생성하고, 선언문만 먼저 실행해서 환경레코드에 미리 기록해두는 단계죠.
그리고 이어서 선언문 외에 나머지 코드를 순차적으로 실행하는데 이 단계를 실행 단계라고 합니다.
필요한 경우 환경레코드에 기록해둔 정보를 참고하거나 업데이트 하게 됩니다.
생성단계 : Creation Phase
Execution Context 생성, 선언문만 실행해서 Environment Record에 기록
실행단계 Excution Phase
Environment Record를 참조하거나 업데이트
다시 코드를 살펴보면서 실행단계에 대해서 설명 드리면
console.log(OTTService); // undefined
var OTTService = "Netflix";
console.log(OTTService); // Netflix
첫번째로 OTTService 의 값을 출력하는 콘솔로그가 실행됩니다.
콘솔로그의 값을 출력하려면 OTTService에 바인딩된 값이 무엇인지 알아내야겠죠?
자바스크립트 엔진은 현재 활성화된 실행컨텍스 내에 환경 레코드를 보고 이미 기록된 OTTService 값을 참조해서 문제없이 값을 출력하게 됩니다. 그래서 undefined를 출력하게 되는 거죠.
그리고 나서 다음 라인의 OTTService 변수를 실행해주게 되는데, 선언은 호이스팅 현상으로 인해 이미 선언 되었으니, 할당만 실행해줍니다. OTTService 변수에 바인딩 된 값을 undefined에서 Netflix로 업데이트 해서 기록해둡니다.
이후 자바스크립트 엔진은 역시 환경 레코드를 참조해서 콘솔로그에서 OTTService 에 바인된 Netflix를 출력하게 됩니다.
여기까지가 var 에 대한 호이스팅 설명인데요.
만약 OTTService 가 var 가 아닌 let과 const로 변수를 선언하면 어떻게 될까요?
console.log(OTTService); // Reference Error
undefined
let OTTService = "Netflix";
console.log(OTTService); // Netflix
let 과 const의 경우 마찬가지로 자바스크립트 엔징이 환경레코드에 OTTService 식별자을 기록해두기는 하지만 값을 undifined로 초기화 시켜주지 않습니다.
그래서 자바스크립트 엔진은 값을 읽어 올 수 없어 레퍼런스 에러를 출력하게 됩니다.
이렇게 let 이나 const으로 선언했을 때, 선언 이전에 식별자를 참조할 수 없는데 이 구역을 일시적 사작지대라고도 합니다.
즉 쉽게 말하자면 var 키워드의 경우 선언과 초기화를 동시에 진행하지만
let과 const 키워는 선언만 해주는 것입니다.
함수 호이스팅(Function Hoisting)
다음으로는 함수 호이스팅에 대해서 살펴보겠습니다.
/ * Global */
study();
function study() {
// do study
}
함수 선언문 방식으로 함수를 선언하는 경우에는
자바스크립트 엔진이 study 함수의 선언과 동시에 완성된 함수 객체를 생성해서 환경레코드에 기록해둡니다.
{ study : f {} }
그리고 study 함수를 실행하면 위치에 상관없이 study 함수가 에러 없이 실행됩니다.
즉, 이런식으로 함수 선언문 방식으로 함수를 작성하고 실행할 경우 선언과 동시에 함수가 생성되어 선언 전에도 함수를 사용할 수 있습니다.
/ * Global */
study();
var stud y= ()=>{
// do study
}
그러나 이런 식으로 변수에 담아서 함수를 선언식이 아닌 표현식으로 작성해줄 경우 위에서 변수 호이스팅에서 설명한 것처럼 똑같이 적용되어 var의 경우는 undefined로 값을 초기화해주지만 함수에서 undefined는 출력할 수 없어 타입에러가 발생하며 let과 const의 경우는 마찬가지로 레퍼런스 에러가 발생합니다.
그래서 함수 사용시 이러한 차이점을 알고 사용하면 혼란 없이 사용하실 수 있으실 겁니다.
이걸로 호이스팅에 대한 포스트는 마치고 다음에는 스코프(Scope)에 대해 알아보고자 합니다.
'Javascript' 카테고리의 다른 글
자바스크립트 JavaScript : 클로저(Closure) (0) | 2024.04.08 |
---|---|
자바스크립트 JavaScript : 스코프(Scope) (0) | 2024.04.06 |
자바스크립트 JavaScript : 프로미스에서 유용한 함수 (0) | 2024.04.04 |
자바스크립트 JavaScript : async/await (0) | 2024.04.03 |
자바스크립트 JavaScript : Promise (0) | 2024.04.03 |