[JavaScript] 호이스팅과 TDZ

👩‍💻💖·2022년 7월 21일

JavaScript

목록 보기
3/3
post-thumbnail

스코프, 호이스팅, TDZ

  1. 스코프
    ㅇ 스코프 이란?
    - 프로그램 내 변수에 접근할 수 있는 유효 범위/영역

    ㅇ 자바스크립트에서, 스코프 생성 상의 특징
    - 위치에 따른 스코프의 생성 : 전역 범위, 함수 범위, 블록 범위로 생성 가능
    . 전역 스코프 : 프로그램 어디에서나 접근 가능 (var 선언자)
    . 함수 스코프 : 함수 내에서 만 접근 가능 (var 선언자)
    . 블록 스코프 : 해당 블록 내에서 만 접근 가능 (let 선언자, const 선언자)
    - 시간에 따른 스코프의 생성
    - 정적 스코프 (정적 메모리 할당)
    . 컴파일러 번역 시에, 변수 영역이 결정됨
    . 어휘적 범위(Lexical Scope, 렉시컬 스코프) 라고도 함
    . 함수를 정의할 때, 구문 해석 만으로도,
    .. 어떤 변수가 그 함수 스코프에 있는지를 알 수 있음
    . 즉, 코드 작성 시점에 스코프가 결정됨
    - 동적 스코프 (동적 메모리 할당)
    . 실행시에 만 비로소 변수 영역이 결정점
    . 함수를 실행할 때 만, 비로소 어떤 변수가 그 함수 스코프에 있는지 알 수 있게됨

  2. 호이스팅 (Hoisting)
    JavaScript에서 호이스팅(hoisting)이란, 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미합니다. var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화합니다. 반면 let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.

    function sayHi() {
    phrase = "Hello"; // (*)
    
    if (false) {
      var phrase;
    }
    
    alert(phrase);
    }
    sayHi()

    바로 위 예제에서 if (false) 블록 안 코드는 절대 실행되지 않지만, 이는 호이스팅에 전혀 영향을 주지 않습니다. if 내부의 var 는 함수 sayHi의 시작 부분에서 처리되므로 (*)로 표시한 줄에서 phrase는 이미 정의가 된 상태인 것이죠. 선언은 호이스팅 되지만 할당은 호이스팅 되지 않습니다.

    ㅇ 변수 호이스팅 (Variable Hoisting)
    - 변수 선언의 끌어올림
    . 중간 부분에서 변수 선언을 하여도,
    . 마치 그 변수가 첫머리에 선언된 것 처럼 취급됨
    - 결국, 변수 선언 및 변수 할당이 분리됨

    ㅇ 함수 호이스팅 (Function Hoisting)
    - 함수 선언의 끌어올림
    . 함수 선언문 형태(명시적 함수)로 정의한 함수의 유효 범위는,
    . 코드의 맨 처음부터로 취급됨
    * 단, 함수 표현식 형태로 선언되는 경우는 호이스팅되지 않음
    ※ 호이스팅은, 자바스크립트 고유한 특성으로 다른 프로그래밍 언어와는 차별됨
    var만의 특성은 대부분의 상황에서 좋지 않은 부작용을 만들어낸다. let이 표준에 도입된 이유가 바로 이런 부작용을 없애기 위해서이다. 변수는 블록 레벨 스코프를 갖는 게 좋으므로 이제는 let과 const를 이용해 변수를 선언하는 게 대세가 되었다.

  3. TDZ (Temporal Dead Zone)
    TDZ 시맨틱은 선언 전에 변수에 접근하는 것을 금지한다. TDZ는 징계를 내린다: 변수 선언 전에 어떤 것도 사용하지 않는다.
    TDZ_Structure ref. https://dmitripavlutin.com/javascript-variables-and-temporal-dead-zone/

    자바스크립트는 정의되지 않았지만 변수의 메모리 할당 단계 호이스팅이 발생하고 스레드 실행 단계에서 변수에 액세스할 수 있으므로 결과적으로 값이 정의되지 않은 것으로 나타난다. let & const 가 사용되었을 때 자바스크립트 개발자가 좋은 코드를 작성하고 디버깅을 쉽게 하기 위해 액세스에 대한 몇 가지 제한이 있다. 그래서 TDZ 새로운 개념이 등장하여 제공하기 전에 일부 데이터에 액세스하기 때문에 오류를 잡는 데 도움이 된다.

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

ㅇ 함수 호이스팅 (Function Hoisting)
- 함수 선언의 끌어올림
. 함수 선언문 형태(명시적 함수)로 정의한 함수의 유효 범위는,
. 코드의 맨 처음부터로 취급됨
ㅇ 함수 표현식 호이스팅 X => 변수 호이스팅
변수 호이스팅은 변수 생성 및 초기화와 할당이 분리되어 진행된다. 호이스팅된 변수는 undefined로 초기화 되고 실제값의 할당은 할당문에서 이루어진다.

let, const, var

  1. 변수 선언
    ㅇ 명시적인 변수 선언은,

    • var,let 라는 예약어 만으로 가능

    ㅇ 변수명 규칙

    • 영문자, $, _ (3 종류) 만으로 시작해야 함
    • ② 대소문자 구분
    • ③ 다만, 각 변수가 유일한 이름 만 있으면 됨
  2. 상수 선언
    ㅇ const 키워드로 선언

    ㅇ 특징

    • 블록 단위 스코프
    • 선언시 반드시 초기값 할당해야 함
    • 재할당(변경) 불가
    • 상수로 선언된 배열,객체 내부의 값 변경은 가능

함수 (Function)

  1. 함수 이란?

    ㅇ [프로그래밍 일반]

    • 함수란 일단 정의되면 여러번 호출되며 실행될 수 있는 프로그램 블록

    ㅇ [자바스크립트 언어]

    • 자바스크립트 함수는, 매우 다양한 기능, 독특한 특징들이 있음
    • C 언어의 함수,자바 언어의 메서드 등과는 달리,
      . 그 자신이 객체이며,
      . 다른 객체를 생성할 수 도 있으며,
      . 실행 execute 가능(호출 invoke 가능),참조 reference 가능 특징 둘다 갖는 특별한 객체임
  1. 자바스크립트 함수의 특징 (통상의 프로그래밍 언어와의 차별점)

    ㅇ 함수를 값 처럼 할당/대입할 수 있으며, 그 방법이 다양함

    • 변수에 함수를 할당할 수 있음
      . 함수명과 변수명의 경계가 모호함 (명칭 만으로는 구분이 안됨)
    • 객체의 프로퍼티에 함수를 할당할 수 있음
    • 배열 내 원소에도 함수를 할당(정의,저장)할 수 있음

    ㅇ 함수를 매개변수로 전달할 수도 있으며, 함수 그 자체를 반환할 수도 있음

    • 즉, 함수를 다른 함수에 의해 인수로써 전달 또는 결과로써 반환할 수 있음
      . 함수 그 자체가 인수나 리턴 값으로 사용할 수 있음
    • 이를두고 1급 객체 (First Class Object) 또는 고차 함수(Higher-order Function) 라고도 함
      . 따라서, 함수형 언어 처럼 함수형 프로그래밍이 가능함

    ㅇ 함수 정의(생성) 방식이 다양함 관련 링크

    • 명시적 함수(함수 선언문) 형식에 의한 방법 이외에도,
    • 익명 함수 형식
    • 함수 리터럴 형식
    • 함수 객체 생성자 형식 등
    • 즉, 정적 및 동적으로 모두 생성 가능

    ㅇ 자바스크립트 함수는 일종의 객체 임 ☞ Function 객체, 자바스크립트 객체 참조

    • 그 안에 그만의 독특한 프로퍼티,메소드가 있게 됨
      . 프로퍼티 : length (인수 갯수), name (함수 이름), arguments, caller, prototype
      . 메소드 : apply(), bind(), call(), ☞ this 키워드 참조
      constructor, toString() 등
    • 또한, 상위 프로토타입 객체(Function.prototype)를 상속 받아서 사용 가능
      . 例) __proto__라는 접근자 프로퍼티는, Object.prototype 객체의 프로퍼티를 상속 받음
    • 또한, 통상의 객체 처럼, 함수 내에 프로퍼티도 추가 가능
      . 즉, 함수 자체가 일반 객체 처럼 프로퍼티를 갖을 수 있음(추가할 수 있음)

    ㅇ 객체 형태이긴 하나, 하나의 독립된 데이터타입으로 취급됨

    • String object,Number object,Date object 등의 다른 객체 타입과 유사하게 취급됨
  1. 자바스크립트 함수의 생성 방법 및 함수 형태의 종류

    ※ 함수 생성 방법의 종류

    • 명시적 함수, 익명 함수, 함수 리터럴 등

    ㅇ 함수 형태의 종류

    • 즉시실행함수, 화살표함수, 익명함수, 콜백함수, 중첩함수 등
  1. 자바스크립트 함수에서의 인수(매개변수,파라미터)

    ※ ☞ 자바스크립트 함수 인수 참조

  1. 자바스크립트 함수 호출 및 참조

    ㅇ 함수 호출(invoke) : 함수명 뒤에 소괄호 ()를 쓰면 호출(실행)됨

    ㅇ 함수 참조(reference) : 함수명 뒤에 괄호()를 쓰지 않으면, 함수를 참조 만 함

    • 이때에는, 변수,객체 프로퍼티,배열 원소 등에 할당시켜, 단순히 참조 만 가능
    • 즉, 자바스크립트는, 함수를 값 처럼 할당,리턴이 가능하여, 프로그래밍에 유연성을 줌
  1. 함수 메모이제이션 (Memoization)

    ㅇ 함수를 호출했을 때, 그 인수와 반환값을 한 쌍으로 만들어 저장해 두는 기법

실행 컨텍스트

  1. 컨텍스트

    상황, 맥락, 문맥 상의 의미 등으로 이해되는 용어

    ㅇ 사실상, 컨텍스트는,

    • 그냥 텍스트(Text) 처럼 바로 이해되는 단순히 원본 정도가 아니라,
    • 문맥 및 상황에 따라, 어떤 해석이 가미되어 이해되는 한 차원 높은 공간, 영역을 의미

    ㅇ 전산 뿐만 아니라 방송, 예술 등의 분야에서도 널리 사용되는 용어

  1. 전산] 컴퓨터 내부 (하드웨어 관점)

    ㅇ 컨텍스트는 컴퓨터 내부에서 볼 때,

    • 프로세서 안에 있는 레지스터, 플래그 등의 현재 값/상태들의 집합을 말함

    ㅇ Context Switching (문맥 교환)

    • 멀티태스킹 작업을 수행하면서,
    • 각 태스크들을 순서있게 교체 수행하기 위해,
    • 태스크 상태 정보를 레지스터들에 저장 또는 이전 상태를 불러오기위한 작업으로써,
    • 실제 프로그램을 수행하는 작업은 아님
  1. 전산] 프로그램 내부 (소프트웨어 관점)

    ㅇ 그때그때 상황에 맞게끔, 실행/판단/결정 등을 해야하는 부분

    • 例) 할당 연산자(=) 다음에는, 표현식 컨텍스트가 옴
    • 例) if 조건문 다음에 { 가 오면, 문장 컨텍스트가 옴
    • 例) 컨텍스트 메뉴 (context menu)
      . 그 메뉴를 호출한 동작 및 상황에 따라, 다르게 선택 사항들이 나열되는 메뉴
  1. 전산] 자바스크립트 실행 컨텍스트 (Execution Context)

    ㅇ 실행에 필요한 다양한 정보를 형상화하고, 이들을 목록화 관리하기 위한, 추상적인 개념

    • 실행 가능한 코드가 실행되는 프로그램 환경
      . 현재 실행중인 부분
    • 결국, 실행에 필요한 정보들로써,
      . 변수 등의 유효 범위(Scope),유효 기간(Lifetime)의 결정을 위한 환경 정보들
      . 실행에 필요한 정보들의 例)
      .. 변수들 (전역변수, 지역변수, 매개변수, 객체의 프로퍼티)
      .. 함수 선언 정보
      .. 변수의 유효범위(Scope)
      .. this가 가리키는 것 등

    ㅇ 실행 컨텍스트의 관리 및 보유 형태

    • 관리 형태
      . 실행에 필요한 여러 정보들을, 객체 형태로 담아 스택(LIFO)으로 관리
      (Last In First Out)
    • 보유 형태
      . { 렉시컬 환경 : (환경 레코드 + 외부 렉시컬 환경에 대한 참조) }

    ㅇ 만일, 자바스크립트 엔진이,

    • 실행 가능한 코드를 만나면, 그 코드를 평가해서, 실행 컨텍스트를 만들어냄
      . 例)
      .. 만일, 함수를 호출하면,
      .. 현재 실행중인 코드의 작업을 잠시 멈추고,
      .. 함수 코드가 평가되면서,
      .. 실행 컨텍스트 영역을 생성하고,
      .. 이때 생성된 함수 실행 컨텍스트는, 실행 컨텍스트 스택에 푸시되고,
      .. 실행 흐름이, 실행 컨텍스트 스택 상의 그 실행 컨텍스트로 이동하고,
      .. 함수 안팎의 환경을 찾아내어, 실행되어지며,
      .. 함수 실행이 종료되면, 실행 컨텍스트 스택에서 팝되어 제거됨

    • 실행 가능한 코드의 例)
      . 전역 코드 : 가장 바깥쪽에 존재하는 것
      . 함수 코드
      . eval 함수
      . 모듈 코드

콜 스택 (Call stack)

콜 스택이란, 함수의 호출을 스택 방식으로 저장하는 자료구조이다. 즉, 실행 컨텍스트에 콜 스택을

실행 중인 함수의 실행 절차에 대한 정보는 해당 함수의 실행 컨텍스트(execution context) 에 저장됩니다.

실행 컨텍스트는 함수 실행에 대한 세부 정보를 담고 있는 내부 데이터 구조입니다. 제어 흐름의 현재 위치, 변수의 현재 값, this의 값(여기선 다루지 않음) 등 상세 내부 정보가 실행 컨텍스트에 저장됩니다.

함수 호출 일 회당 정확히 하나의 실행 컨텍스트가 생성됩니다.

함수 내부에 중첩 호출이 있을 때는 아래와 같은 절차가 수행됩니다.

현재 함수의 실행이 일시 중지됩니다.
중지된 함수와 연관된 실행 컨텍스트는 실행 컨텍스트 스택(execution context stack) 이라는 특별한 자료 구조에 저장됩니다.
중첩 호출이 실행됩니다.
중첩 호출 실행이 끝난 이후 실행 컨텍스트 스택에서 일시 중단한 함수의 실행 컨텍스트를 꺼내오고, 중단한 함수의 실행을 다시 이어갑니다.

그냥, 여기 가면 잘 나와 있어서, 아래 글을 참고해서 보는 것이 나을 것 같다.
정확히는 콜 스택 보다는, JavaScript의 이벤트 루프에 관한 글이지만, 구동 원리에 대해 이해하는데 추천
https://meetup.toast.com/posts/89

스코프 체인, 변수 은닉화

  • 스코프 체인
    스코프가 연결되어 있음을 말함
function a(){
  // 여기서 r 정의
  var r = 1;
  function b(){
    // 여기선 r 정의는 하지 않아도 r의 값이 출력이 된다.
    console.log(r);
  }
 b();
}

// 이렇게 r을 var 선언해도, a() 호출하면 값으로 1나옴
// 이런식으로 스코프 체인이 형성됨
var r= 2;

a(); //1
  • 변수 은닉화
    변수 은닉화는 변수가 전역 범위에 노출되지 않고, 지역 범위에 노출되게 하면서 전역범위에 불렀을 때 불러 올 수 있게끔 만드는 것인데, 주로 즉시 실행 함수 표현식(immediately-invoked function expressions) 을 이용하여 만들 수 가 있다.

    • 클로져 이용(Closer)
    1. 클로저 (Closure)

      ㅇ 함수와 함수의 참조환경

      ㅇ 부모 함수의 지역 변수의 참조를 갖는 자식 함수 블록

      • 어떤 부모 함수가 그 내부에 있는 자식 함수를 호출할 때,
      • 자식 함수가 그 부모 함수의 지역 변수를 참조하는 경우
    2. 클로저의 특징

      ㅇ 변수를 은닉하여 지속성을 보장할 수 있는 등
      - 특정 스코프 내 함수를 정의하면,
      - 해당 스코프는 더 오래 유지 됨

      ㅇ 접근 못하던 것에 대한 접근 방법이 생김
      - 함수를 정의해서 클로저를 만들면,
      - 접근할 수 없었던 것들에 대해 접근할 방법이 생김

      ㅇ 데이터와 데이터를 조작하는 함수를 하나로 묶을 수 있음
      - 마치 객체지향 프로그래밍과 유사하게 취급 가능

      . 클로저를 감싸고 있는 부모 함수 => 생성자
      . 클로저를 참조하는 외곽 함수 내 지역 변수 => 프로퍼티
      . 클로저 자신 => 메소드
      . 함수 호출 = > 인스턴스화
      . 반환되는 클로저를 대입하게된 변수 => 인스턴스

      ㅇ [자바스크립트]
      - 자바스크립트의 모든 함수는, 클로저를 정의 가능

    • 즉시 실행 함수 (IIFE) 이용

      ㅇ 함수 정의 및 호출/실행이 동시에 이루어지는 함수 형태

      • 함수 표현식으로써 익명 함수를 만들고는, 그 즉시 함수 호출을 함
        . 그 내부에 자신 만의 스코프를 갖고있어,
        . 외부에서 접근할 수 없지만,
        . 즉시실행함수(IIFE) 자체는 함수이므로,
        . 그 스코프 밖으로 변수,배열,함수,객체 등을 반환/내보낼 수 있음

      ㅇ 구문 형식 : (function () { ... })();

      • 통상, 함수 이름이 없는 익명 함수의 사용이 일반적임
    • Class 이용 - 모던 자바스크립트
      getter를 이용하여, 주어진 값을 꺼내 쓸 수 있다.

과제

let b = 1;

function hi () {

const a = 1;

let b = 100;

b++;

console.log(a,b);

}

//console.log(a);

/////////////////////////////////////////
  
console.log(b);

hi();

console.log(b);
let b = 1;
let a; // 전역변수에 a를 추가

function hi () {

a = 1;
let b = 100;
b++;

console.log(a,b);

}

// a가 b와 달리 접근이 가능하지 않은 것은 함수 내부에서만 접근 가능하고
// 함수를 불러야지만, 변수에 접근 가능한 상태로 은닉화를 시킨 형태이다.
console.log(b); // 1 
// 함수를 실행 뒤에 a를 출력할 수 잇다.
hi(); //1 101
console.log(a) // 1

console.log(b); // 1

ref. https://ko.javascript.info/var, https://www.geeksforgeeks.org/what-is-the-temporal-dead-zone-in-es6/, http://www.ktword.co.kr/, https://ui.toast.com/weekly-pick/ko_20191014?fbclid=IwAR3fiR4wiv8kszL6Fz2KqwHpv-bTL8tNHElRN0q0ky5kpOP5BMqMS0wc-9k, https://ko.javascript.info/recursion,

0개의 댓글