[Javascript] 호이스팅과 TDZ는 무엇일까 ?

YES31·2022년 11월 18일
0

javascript

목록 보기
3/4
post-thumbnail

스코프, 호이스팅, TDZ

스코프(Scope)🎈

  • 전역 스코프(Global scope) :
    코드 어디에서든지 참조할 수 있다.

  • 지역 스코프 (Local scope or Function-level scope) :
    함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.

먼저 간단한 예시를 보자.

var x = 0;
{
  var x = 1;
  console.log(x); // 1
}
console.log(x);   // 1

let y = 0;
{
  let y = 1;
  console.log(y); // 1
}
console.log(y);   // 0

자바스크립트는 함수 레벨 스코프(function-level scope)를 따른다. 함수 레벨 스코프란 함수 코드 블록 내에서 선언된 변수는 함수 코드 블록 내에서만 유효하고 함수 외부에서는 유효하지 않다(참조할 수 없다)는 것이다.
.
.

Gloval Scope 🎁

전역에 변수를 선언하면 이 변수는 어디서든지 참조할 수 있는 전역 스코프를 갖는 전역 변수가 된다. var 키워드로 선언한 전역 변수는 전역 객체(Global Object) window의 프로퍼티이다.

var global = 'global';

function foo() {
  var local = 'local';
  console.log(global);
  console.log(local);
}
foo();

console.log(global);
console.log(local); // Uncaught ReferenceError: local is not defined

변수 global는 함수 영역 밖의 전역에서 선언되었다. 자바스크립트는 타 언어와는 달리 특별한 시작점(Entry point)이 없어서 위 코드와 같이 전역에 변수나 함수를 선언하기 쉽다.


하지만 자바스크립트는 다른 C-family language와는 달리 특별한 시작점이 없으며 코드가 나타나는 즉시 해석되고 실행된다. 따라서 전역에 변수를 선언하기 쉬우며 이것는 전역 변수를 남발하게 하는 문제를 야기시킨다.

.
.
함수 레벨 스코프(Function-level scope) 🎁

var x = 'global';

function foo() {
  var x = 'local';
  console.log(x);
}

foo();          // local
console.log(x); // global

전역변수 x와 지역변수 x가 중복 선언되었다. 전역 영역에서는 전역변수만이 참조 가능하고 함수 내 지역 영역에서는 전역과 지역 변수 모두 참조 가능하나 위 예제와 같이 변수명이 중복된 경우, 지역변수를 우선하여 참조한다.
.
.

var foo = function ( ) {
  	var a = 3, b = 5;
  
  	var bar = function ( ) {
   		 var b = 7, c = 11;
// 이 시점에서 a는 3, b는 7, c는 11
    		a += b + c;
// 이 시점에서 a는 21, b는 7, c는 11
  	};

// 이 시점에서 a는 3, b는 5, c는 not defined
  bar( );
// 이 시점에서 a는 21, b는 5
};

호이스팅

함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다.

  • 자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.

    • 자바 스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.
    • 함수 안에 존재하는 변수/함수선언에 대한 정보를 기억하고 있다가 실행시킨다.
    • 유효 범위 : 함수 블록 {} 안에서 유효
  • 즉, 함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 끌어올리는 것이다.

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

호이스팅 대상🎋

  • var변수 선언과 함수선언문에서만 호이스팅이 일어난다.
    • var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
    • let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.

TDZ (Temporal Dead Zone)

스코프의 시작 지점부터 초기화 시작 지점까지의 구간
TDZ를 설명하기 위해 먼저 변수의 선언 단계를 집고 넘어가려한다.


javascript에서의 변수는 위의 사진처럼 선언, 초기화, 할당이라는 3가지 단계의 걸쳐서 생성된다.

  • 선언 단계(Declaration phase) : 변수를 실행 컨텍스트의 변수 객체에 등록하는 단계를 의미한다. 이 변수 객체는 스코프가 참조하는 대상이 된다.
  • 초기화 단계(Initialization phase) : 실행 컨텍스트에 존재 하는 변수 객체에 선언 단계의 변수를 위한 메모리를 만드는 단계이다. 이 단계에서 할당된 메모리에는 undefined로 초기화된다.
  • 할당 단계(Assignment phase) : 사용자가 undefined로 초기화된 메모리의 다른 값을 할당하는 단계

var

var 키워드 변수는 변수 선언전에 선언 단계와 초기화 단계를 동시에 진행한다.
그래서 javascript는 실행 컨텍스트 변수 객체의 변수를 등록하고 메모리를 undefined로 만들어 버린다. 그렇기 때문에 변수를 선언하기 전에 호출을 해도 undefined로 호출이 되는 호이스팅이 발생하는 것이다.


let

let으로 선언된 변수는 var 키워드와는 다르게 선언단계와 초기화 단계가 분리되어서 진행이 된다. 그렇기 때문에 실행 컨텍스트에 변수를 등록했지만, 메모리가 할당이 되질 않아 접근할 수 없어 참조 에러(ReferenceError)가 발생하는 것 이고, 이것을 보고 우리가 호이스팅이 되질 않는다!! 라고 오해할 수 밖에 없었던 것이다.

TDZ : 스코프의 시작 지점부터 초기화 시작 지점까지의 구간 ❗❗❗

.
.
.

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

함수 선언식 (Function Declarations)

일반적인 함수 선언 방식

function funcDeclarations() {
    return 'enchovy';
}
 
funcDeclarations();

함수 표현식 (Function Expressions)

자바스크립트 언어의 특징을 활용한 선언 방식

let funcExpression = function () {
    return 'enchovy';
}
 
funcExpression();
ES6에서 추가된 화살표 함수 방식을 정의할 수도 있다.

let funcArrow = (x,y) => (x+y)

함수 선언식과 표현식의 차이

스코프와 호이스팅
함수 선언문은 var와 같이 함수 스코프(function scope)를 가지고 letconst 변수는 블록 스코프(block scope)를 갖는다. 또한, 함수 선언식은 코드가 실행되기 전에 로드되지만, 함수 표현식은 interpreter가 해당 코드 줄에 도달할 때 로드된다. 함수 선언식은 호이스팅 되지만 함수 표현식은 호이스팅 되지 않으므로 정의된 범위에서 로컬 변수의 복사본을 유지할 수 있다.

/ 선언 전에 호출되도 정상 동작된다
// 1
console.log(enchovy());
function enchovy() {
    return 1;
}
때문에 함수 선언식은 블록문 밖에서 호출이 가능하다. 

 // 로드되지 않아 error 발생
console.log(enchovy());
const enchovy = function() {
    return 1;
}
함수 표현식은 선언한 변수에 할당하는지에 따라 스코프가 달라진다.
profile
🏀 주니어 개발자

0개의 댓글