Javascript - 호이스팅 / TDZ

SeowooCHo2·2022년 5월 21일
0

Javascript

목록 보기
3/4
post-thumbnail

호이스팅과 TDZ를 알기 전 먼저 스코프에 대해 알아야 한다.😃

  • 자바스크립트는 코트의 영역을 스코프로 나누어 관리한다.

  • 스코프는 단방향으로 연결되는 체인을 형성하며, 이 스코프 체인을 통해 상위 스코프로 이동하면서 식별자를 검색한다.

  • 클로저와 밀접한 관계를 갖기 때문에 꼭 알아두어야하는 개념

스코프(Scope)💘

식별자의 유효 범위

모든 식별자는 자신이 선언된 위치에 의하여 다른 코드가 식별자 자신을 참조할 수 있는 유효 범위가 결정된다.

네임스페이스

한 스코프 내에서는 식별자가 유일해야 하지만, 다른 스코프에는 동명의 식별자를 사용할 수 있음.

식별자 결정(identifier resolution)

자바스크립트 엔진은 스코프를 통해서 어떤 변수를 참조할 것인지 결정함.

스코프의 종류

1. 전역 스코프(global scope)

전역은 코드의 가장 바깥 영역으로, 여기서 선언된 변수는 전역 변수가 됨.

전역 변수는 어디서든 참조 가능

2. 지역 스코프(local scope)

지역은 함수 코드의 내부 영역으로, 여기서 선언된 변수는 지역 변수가 됨.

지역 변수는 자신의 지역 스코프 및 하위 지역 스코프에서 참조 가능

3. 함수 레벨 스코프 VS 블록 레벨 스코프

지역 스코프는 함수에 의해서 생성되는가, 코드 블록에 의해서 생성되는가에 따라 레벨이 나뉨.

블록 레벨 스코프

  • if, for, while, try/catch 등 코드 블록이 지역 스코프 생성

  • let, const 키워드로 선언된 변수는 모든 코드 블록을 지역 스코프로 인정함.

함수 레벨 스코프

  • 함수가 지역 스코프 생성

  • var 키워드로 선언된 변수는 오직 '함수'만을 지역 스코프로 인정함.

4. 렉시컬 스코프 ( 정적 스코프 / lexical scope )

  • 자바스크립트에서는 함수 정의가 평가되는 시점에 상위 스코프가 정적으로 결정됨.

  • 즉, 함수를 어디서 호출했는지가 아니라 '어디에 정의했는지'에 따라서 상위 스코프가 결정됨.

  • 함수의 상위 스코프는 함수 정의가 실행될 때 정적으로 결정되며, 함수 정의가 실행되어 생성된 함수 객체는 상위 스코프를 기억함.
    ⇒ 클로저와 깊은 연관

  • 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다.
  • 간단히 말하면 클로저는 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수다

스코프 체인(Scope Chain)



스코프는 함수의 중첩에 의해 계층적 구조를 가진다.

  • 외부 함수(outer function)
  • 중첩 함수(nested function)

변수를 참조할 때, 자바스크립트 엔진은 스코프 체인을 통해
변수를 참조하는 코드의 스코프 =>>> 상위 스코프로 이동
선언된 변수를 검색한다.

변수 은닉화(variable shadowing)💨💨

  • 여러 스코프에서 동일한 식별자를 선언한 경우, 무조건 스코프 체인 상에서 가장 먼저 검색된 식별자에만 접근 가능

스코프 체인은 outerEnvironmentReference와 밀접한 관계를 가짐.


TDZ( Temporal Dead Zone)🍟

일시적으로 죽은 공간이라는 뜻

무슨 의미일까?? 🤔

  • 스코프의 시작 지점부터 초기화 시작 지점까지의 구간
let a = 1;
{
  console.log(foo);
  let a = 2;
}

간단히 여기서 중괄호 안의 구역을 TDZ라고 한다

  • var은 TDZ의 영향을 안받는다
  • let, const는 TDZ의 영향을 받고 이 떄문에 Reference Error가 출력되는 것이다.

호이스팅🌮

  • 호이스팅은 코드를 실행하기 전 변수선언/함수선언을 해당 스코프의 최상단으로 끌어올리는 것이 아니다.

  • 호이스팅은 코드가 실행하기 전 변수선언/함수선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상을 말한다.

  • 자바스크립트 엔진은 코드를 실행하기 전 실행 가능한 코드를 형상화하고 구분하는 과정( 실행 컨텍스트를 위한 과정 )을 거친다.

  • 자바스크립트 엔진은 코드를 실행하기 전 실행 컨텍스트를 위한과정에서 모든 선언(var, let, const, function, class)을 스코프에 등록한다.

  • 실행 컨텍스트는 실행 가능한 코드가 실행되기 위해 필요한 환경을 의미하고 실행되기전 이러한 실행 컨텍스트 과정(코드를 구분하는 과정)을 거친다.

변수 호이스팅 (var, let, const 키워드)🍿

  • 자바스크립트의 모든 선언에는 호이스팅이 일어난다.

  • 하지만 let, const, class를 이용한 선언문을 호이스팅이 발생하지 않는 것처럼 동작한다.

이런 이유가 무엇일까??🤔

이는 var, let, const의 호이스팅 단계가 다르기 때문이다( ̄︶ ̄)↗ 

1단계: 선언 단계(Declaration phase)📕

  • 변수를 실행 컨텍스트의 변수 객체에 등록한다.
  • 이 변수 객체는 스코프가 참조하는 대상이 된다.

2단계: 초기화 단계(Initialization phase)📗

  • 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다.
  • 이 단계에서 변수는 undefined로 초기화 된다.

3단계: 할당 단계(Assignment phase)📘

  • undefined로 초기화된 변수에 실제 값을 할당한다.

var의 호이스팅 단계📕📗 => 📘

  1. 선언 && 초기화
  2. 할당

let의 호이스팅 단계📕 => 📗 => 📘

  1. 선언
  2. 초기화
  3. 할당

const의 호이스팅 단계📕📗📘

  1. 선언 && 초기화 && 할당

무슨 의미인지 아래 코드를 보고 이해해보자!!

var a = 1;
{
  console.log(a);
  var a = 2;
}

// 1출력

var는 호이스팅 시 선언 && 초기화가 동시에 발생하여 출력 이후 지정된 변수는 undefined로 초기화 되고 전역변수로 선언된 1이 출력된다

let a = 1;
{
  console.log(a);
  let a = 2;			//TDZ에 갇힘
}

// Reference Error(참조 에러)

let은 호이스팅 시 선언이 이루어진 후, 할당라인에서 초기화 => 할당으로 진행되기 때문에 선언은 됐지만 참조가 되지 않아 Referenc Error가 출력된다

const a = 1;
{
  console.log(a);
  const a = 2;		//TDZ에 갇힘
}

// Reference Error(참조 에러)

const는 호이스팅 시 선언 && 초기화 && 할당이 동시에 이루어져야 하는데 선언만 호이스팅되어 Reference Erorr가 출력된다.

또한 const는 재할당이 되지 않는다


함수 표현식과 함수 선언문의 호이스팅🥚

자바스크립트에서 함수를 선언하는 방법은 2가지가 있다.

  • 함수 표현식
var add = function (x, y) {
    return x + y;
}
  • 함수 선언문
function add(x, y) {
    return x + y;
}

그런데 자바스크립트 Guru로 알려진 더글러스 크락포드는 함수 생성에 있어서 함수 표현식만을 사용할 것을 권하고 있단다!!( ̄︶ ̄)↗

그 이유가 뭘까?? 🤔

  • 그 이유는 함수 표현식과 함수 선언문의 호이스팅 차이 때문이라고 한다!!

함수 선언문의 호이스팅

console.log(add(2, 3));	// 5 출력
 
function add(x, y) {
    return x + y;
}
 
console.log(add(3, 4));	// 7 출력

보다시피 함수가 선언되기 전에 함수를 호출해도 Error가 출력되지 않는다.

즉, 함수가 자신이 위치한 코드에 상관없이 함수 선언문 형태로 정의한 함수의 유효 범위는 코드의 맨 처음부터 시작한다는 것을 확인할 수 있다.

함수 표현식의 호이스팅

console.log(add(2, 3));  // error
 
// 함수 표현식 형태로 add() 함수 정의
var add = function (x, y) {
    return x + y;
}
 
console.log(add(3, 4));  // 7

함수 표현식으로 함수를 나타내면, 함수가 선언되기 전에 호출하게되면 Error가 발생한다.

즉 더글러스는 함수 선언문으로 코드 작성 시 함수 선언문이 코드의 구조를 엉성하게 만들 수 있다는 점을 지적해 함수 표현식만을 사용하기를 권장한다


실행 컨텍스트🍞

  • 자바스크립트 엔진이 코드를 실행하기 위해선 코드에 대한 정보들이 필요하다.

  • 코드에 선언된 변수함수, 스코프, this, arguments 등을 묶어, 코드가 실행되는 위치를 설명한다는 뜻의 Execution Context라고 부릅니다.

  • 자바스크립트 엔진은 Execution Context객체로 관리하며 코드를 Execution Context 내에서 실행합니다.

Execution Context의 종류

1. Global Execution Context

  • 코드를 실행하며 단 한 개만 정의되는 전역 Context입니다.
  • global object를 생성하며 this 값에 global object참조합니다.
  • 전역 실행 컨텍스트Call Stack에 가장 먼저 추가되며 앱이 종료 될 때 삭제된다.

2. Functional Execution Context

  • 함수가 실행 될 때 마다 정의되는 Context입니다.
  • 전역 실행 컨텍스트가 단 한 번만 정의되는 것과 달리, 함수 실행 컨텍스트는 매 실행시마다 정의되며 함수 실행이 종료(return)되면 Call Stack에서 제거된다.

3. Eval Context❌

  • eval 함수로 실행한 코드의 Context이다.
  • 보안상 취약한 점이 있어 비권장 함수이다.

Execution Context의 관리: CallStack 👮‍♂️

  • JS 엔진은 생성된 Context를 관리하는 목적의 Call Stack(호출스택)을 갖고 있다

  • JS단일 스레드 형식이기 때문에 런타임에 단 하나의 Call Stack이 존재한다

  • JS 엔진은 전역 범위의 코드를 실행하며 Global Execution Context를 생성해 stackpush한다.

  • 함수가 실행 또는 종료 될 때마다 Global Execution Context의 위로 Functional Execution Context stackpush(추가), pop(제거)한다.

아래 gif 파일이 이해에 도움이 될 것 이다 ( ̄︶ ̄)↗ 


공부하면서 느낀 점😃

이론적인 배경이 거의 없는 상태에서 코딩을 하다 보면 머릿속으로 생각한 것 처럼 코드를 짜도 출력이 안되거나 오류가 발생하는 경우가 허다했다

그런 부분들을 조금이나마 이해하게되었고, 앞으로 코드 리뷰나 코드 해석을 할 때에 보다 구체적으로 실행 알고리즘이나 오류 발생 원인을 파악할 수 있을 것 같다.

역시 새로운 것을 배우는 건 항상 새롭고 재미있다( ̄︶ ̄)↗ 

profile
먹고 배우는 것엔 아끼지 말자구 ( ̄︶ ̄)↗ 

0개의 댓글