[JS] Hoisting(호이스팅)? TDZ(일시적 사각지대, Temporal Dead Zone)?
Hoisting(호이스팅)? TDZ?
Hoisting(호이스팅)
호이스팅은 함수 안에 정의된 변수의 선언문을 해당 함수 유효 범위(scope)의 최상단으로 끌어올려서 선언하는 것처럼 보이는 현상이야.
*인터프리터(interpreter)가 선언을 하기 전에 "변수와 함수의 메모리 공간"을 "미리 할당"하는 걸 의미해.
변수나 함수를 선언하기 이전에 사용할 수 있기 때문에 가능한 거지. 그래서 끌어 올려지는 것처럼 보이는 거고.
'선언과 할당의 분리'라고 생각하면 기억하기 편해.
즉, 변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는 거야.
따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있단 얘기지.
-> 다만, 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야
*'변수가 초기화 된 상태'가 됐다고 할 수 있어.
변수 초기화란?
- 변수를 선언함과 동시에 값을 넣어주는 걸 의미해
인터프리터(interpreter, 해석기)?
- 프로그래밍 언어의 소스 코드를 바로 실행하는 컴퓨터 프로그램 또는 '환경'을 말해.<위키백과>
<참고 : MDZ>
JavaScript는 함수의 코드를 실행하기 전에 함수 선언에 대한 메모리부터 할당해.
덕분에 함수를 호출하는 코드를 함수 선언보다 앞서 배치할 수 있지.
예시)
function catName(name){
console.log("제 고양이의 이름은 " + name + "입니다");
}
catName("호랑이");
/* 결과
"제 고양이의 이름은 호랑이입니다"
*/
위의 코드 조각이 일반적으로 코드를 작성하는 순서야.
그럼 함수를 선언하기 전에 먼저 호출했을 때의 예제도 볼게.
catName("클로이");
function catName(name){
console.log("제 고양이의 이름은 " + name + "입니다");
}
/* 결과
"제 고양이의 이름은 클로이입니다."
*/
이처럼 함수 호출이 함수 자체보다 앞서 존재하지만, 그럼에도 불구하고 이 코드 역시 동작해.
이게 JavaScript에서 실행 맥락이 동작하는 방식이야. 호이스팅을 여기에 비유할 수 있지.
Javascript는 '선언'만 호이스팅 대상으로 여겨. 변수 선언문, 함수 선언문 등.
프로그램은 작성한 순서에 따라 윗줄부터 차례로 실행되지만,
변수 선언은 이 원칙을 따르지 않아.
var로 선언한 변수의 경우 호이스팅 시, undefined로 변수를 초기화해.
그와 달리
let과 const로 선언한 변수의 경우는 호이스팅 시(변수 선언을 상단으로, 할당만 제자리), 변수를 undefined로 초기화하지않아서 변수의 초기화를 수행하기 전에, 읽는 코드가 먼저 나타나면 예외가 발생해서 참조오류가 나.
그 오류가 나는 구간을 TDZ(일시적 사각지대라고 해. 변수를 선언하기 전엔 아무 것도 사용하지 말라는 구간인데 선언을 해서 하지말라고 하려고 오류(참조오류, reference error)를 보여주는 거지.)
함수 호이스팅
함수의 선언 역시 호이스팅의 대상이야.
그래서 스코프 내에서 어떤 위치에서 함수 선언을 하든 지 호출할 수 있어.
예시 1)
sayName();
function sayName(){
console.log('둘리');
}
<개발자가 작성한 코드>
function sayName(){
console.log('둘리');
}
sayName();
<호이스팅으로 변환된 코드>
함수 선언 역시 최상단으로 끌어올려져서 sayName()을 먼저 호출하고 함수 정의를 이후에 해도
정상적으로 동작해. (이게 호이스팅이 된다고 하고, 호이스팅의 영향을 받는다고 얘기하지.)
예시 2)
sayName();
var sayName = function(){
console.log('둘리');
}
<개발자가 작성한 코드>
var sayName; //호이스팅으로 선언은 위로 할당은 아래 그대로.
sayName(); //Uncaught TypeError: sayName is not a function 오류발생
sayName = function(){//할당 부분
console.log('둘리');
}
<호이스팅으로 변환된 코드>
var sayName은 변수이기 때문이야. 그래서 '선언과 할당'의 분리가 발생해.
순서를 보면, sayName이 선언되고 sayName()이 호출되지만 이 함수엔 아무것도 없어.
그 후에 sayName에 함수가 정의되는 거야( sayName = function(){console.log('둘리');} 이게.).
변수 호이스팅
변수 호이스팅 또한 함수 호이스팅과 같은 부분이 많아.
console.log(num); //호이스팅한 var선언으로 인해 undefined이란 값이 출력.
var num; //선언
num = 6; //초기화(변수에 값을 할당한다)
var같은 경우, 위치 상관없이 선언해도 undefined가 출력되지만,
let과 const로 선언한 변수는 TDZ영역에 들어가게 되서 변수 선언 전에
변수를 먼저 사용하게 되면 오류가 발생하게 돼.
console.log(num); //Reference error : num is not defined;라는 오류발생
let num;
num = 6;
console.log(num);
/* 결과
6
*/
TDZ
TDZ는 Temporal Dead Zone의 약자야.
한글로 직역하면 일시적인 사각지대란 말이지.
이 일시적인 사각지대는 스코프의 시작 지점부터 초기화 시작 지점까지의 구간이라고 해.
선언하기 전에는 아무 것도 사용하지 말란 구간이야 .
변수를 선언하기 전에는 아무 것도 사용하지말라는데 사용하게 되면 "오류"나게 해서 혼내줘. 규칙을 안 지켰으닌까. 그것도 참조오류(Reference Error).
그래서 변수를 선언하고 변수이름을 띄워줘야 안 혼난다.
이건 변수 키워드의 라이프 사이클에서 비롯되는데...
변수 선언의 3단계
javascript에서의 변수는 사진처럼 선언, 초기화, 할당이라는 3가지 단계에 걸쳐서 생성돼.
- 선언단계(Declaration phase)
변수를 실행 컨텍스트의 변수 객체에 등록하는 단계야. 이 변수 객체는 스코프가 참조하는 대상이 돼.
- 초기화 단계(Initialization phase)
실행 컨텍스트에 존재하는 변수 객체에 선언 단계의 변수를 위한 메모리를 만드는 단계야.
이 단계에서 할당된 메모리에는 undefined로 초기화 돼.
- 할당 단계(Assignment phase)
사용자가 undefined로 초기화된 메모리의 다른 값을 할당하는 단계야.
키워드 var 와 let/ const의 차이는 이 3가지 단계의 순서에서 차이가 나.
var 키워드의 라이프사이클
var 키워드는
변수 선언 전에 선언 단계, 초기화 단계를 동시에 진행해.
그래서 javascript는 실행 컨텍스트 변수 객체의 변수를 등록하고
메모리를 undefined로 만들어버려.
그래서 변수를 선언하기 전에 호출을 해도 undefined로 호출이 되는 호이스팅이 발생해.
let 키워드의 라이프 사이클
let으로 선언된 변수는 var 키워드와는 다르게
선언단계와 초기화 단계가 분리되어서 진행이 돼.
그래서 실행 컨텍스트에 변수를 등록해도,
메모리가 할당이 되지않아서 접근할 수가 없어서 참조에러(Reference Error)가
발행하고, 이걸 보고 우린 호이스팅이 되질 않는다, 호이스팅의 영향을 받지 않는다고 해.
그래서 TDZ란 건.
스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 말해.
즉, let 또한 선언 전, 실행 컨텍스트 변수 객체에 등록이 되어 호이스팅은 되지만,
이 TDZ구간에 메모리가 할당이 되지 않아서 참조 에러(ReferenceError)가 발생하는 거지.
추가로, Function 키워드 함수는 변수선언 3단계를 동시에 진행해버려;
- 참고자료 -