HoistingとTDZは何が関係していますか?


📌 がんばってください。


関数のすべての宣言を、関数の有効なスキャンの最上位にドラッグ&ドロップします.
狙いを定める
JavaScriptは、ES 6に導入されたletおよびconstを含むすべての宣言(var、let、const、function、function*、class)をサポートします.護送とは,var宣言や関数宣言などをスキャンの先端に移動する際に用いられる特性である.
let/cont変数宣言および関数式では、エスケープは発生しません.
  foo();
  foo2();

  function foo() { // 함수선언문
          console.log("hello");
  }
  var foo2 = function() { // 함수표현식
          console.log("hello2");
  }

📌 関数宣言文と関数式から選択


関数宣言のエスケープ

  • 関数宣言は、コードがどこで実装されているかにかかわらず、JavaScriptのプロパティに基づいて、ブラウザがJavaScriptを解析するときに上部に押し上げます.
  • /* 정상 출력 */
    function printName(firstname) { // 함수선언문 
        var result = inner(); // "선언 및 할당"
        console.log(typeof inner); // > "function"
        console.log("name is " + result); // > "name is inner value"
    
        function inner() { // 함수선언문 
            return "inner value";
        }
    }
    
    printName(); // 함수 호출 

    関数式のシンボル

  • 関数式は、関数宣言文とは異なり、宣言と呼び出しの順序で正常に動作しない場合があります.
    *関数式では、宣言と割り当ては別々です.
  • /* 오류 */
     function printName(firstname) { // 함수선언문
         console.log(inner); // > "undefined": 선언은 되어 있지만 값이 할당되어있지 않은 경우
         var result = inner(); // ERROR!!
         console.log("name is " + result);
    
         var inner = function() { // 함수표현식 
             return "inner value";
         }
     }
    printName(); // > TypeError: inner is not a function
    関数宣言文と関数式では、記号の役割が異なることに注意してください.変数に割り当てられた関数式はドラッグされないため、変数のスキャンルールに従います.
    質問:printNameで「inner is not defined」エラーが発生せず、「inner is not a function」タイプエラーが発生したのはなぜですか?
    A.printNameランタイム(Hoistingで指定)内部がundefinedとして指定されているためです.
    内部は定義されていません.これは、関数として認識できないことを意味します.

    💡 関数式の宣言は呼び出しの下にあります。

     /* 오류 */
     function printName(firstname) { // 함수선언문
         console.log(inner); // ERROR!!
         let result = inner();  
         console.log("name is " + result);
    
         let inner = function() { // 함수표현식 
             return "inner value";
         }
     }
    
    printName(); // > ReferenceError: inner is not defined
    console.log(inner);内部に宣言されていないため、内部is not definedエラーが発生します.

    カスケード優先度


    💡 同じ名前のvar変数宣言と関数宣言で呼び出されます。

  • 変数宣言は、関数宣言に昇格します.
  •   var myName = "hi";
    
      function myName() {
          console.log("yuddomack");
      }
      function yourName() {
          console.log("everyone");
      }
    
      var yourName = "bye";
    
      console.log(typeof myName);
      console.log(typeof yourName);
      /** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 --- */
      // 1. [Hoisting] 변수값 선언 
      var myName; 
      var yourName; 
    
      // 2. [Hoisting] 함수선언문
      function myName() {
          console.log("yuddomack");
      }
      function yourName() {
          console.log("everyone");
      }
    
      // 3. 변수값 할당
      myName = "hi";
      yourName = "bye";
    
      console.log(typeof myName); // > "string"
      console.log(typeof yourName); // > "string"

    💡 値が割り当てられていない変数と値が割り当てられている変数で呼び出されます。

      var myName = "Heee"; // 값 할당 
      var yourName; // 값 할당 X
    
      function myName() { // 같은 이름의 함수 선언
          console.log("myName Function");
      }
      function yourName() { // 같은 이름의 함수 선언
          console.log("yourName Function");
      }
    
      console.log(typeof myName); // > "string"
      console.log(typeof yourName); // > "function"
  • が指定されていない変数の場合、関数宣言は変数を上書きします.
  • の値が割り当てられた変数の場合、この変数は関数宣言を上書きします.
  • ♥▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼

  • コードの可読性とメンテナンス性を確保するには、クロストークが発生しないことを確認します.
    *コードの上部にできるだけ関数と変数を宣言すると、シースが不明であってもシースによるスキャンの歪みを回避できます.
  • varを使用すると、混乱や不要なコードを引き起こす可能性があります.ではなぜvarとhoistingを理解するのでしょうか.
    *ES 6は、どこでも使用できる時間がかかります.したがって、ダンプファイルをES 5に変換する必要があります.
  • の理由で、varがどのように動作しているかを知る必要があります.
  • 📌 Temporal Dead Zone(TDZ)


    時間帯区分(TDZ)とは?
    宣言前に変数の概念空間を使用することはできません.
    const変数宣言から始めましょう.変数を宣言して初期化すると、その変数にアクセスできます.予定通りに操作します.
    const white = '#FFFFFF';
    
    white; // => '#FFFFFF'
    今回は声明の前にwhite変数にアクセスしてみましょう.
    white; // throws `ReferenceError`
    const white = '#FFFFFF';
    
    white; // => '#FFFFFF'
    const white=「#FFFFF」構文の前の行に、白い変数がTDZにあります.
    TDZの白い変数にアクセスすると、ReferenceError:Cannot access"White"は初期化前に JavaScriptエラーが発生しました.

    📌 TDZの影響を受ける構文


    const変数


    cont変数は、前の行が宣言および初期化されるまでTDZにあります.
    // Does not work!
    pi; // throws `ReferenceError`
    const pi = 3.14;
    cont変数は宣言後に使用する必要があります.
    const pi = 3.14;
    
    // Works!
    pi; // => 3.14

    89 let変数


    前の行を宣言する前にletもTDZの影響を受けます.
    // Does not work!
    count; // throws `ReferenceError`
    let count;
    
    count = 10;

    クラス構文


    タイトルセクションでご覧のように、宣言前にclassは使用できません.
    // Does not work!
    const myNissan = new Car('red'); // throws `ReferenceError`
    
    class Car {
      constructor(color) {
        this.color = color;
      }
    }
    上記の例を有効にするには、クラスを宣言した後に変更する必要があります.
    class Car {
      constructor(color) {
        this.color = color;
      }
    }
    
    // Works!
    const myNissan = new Car('red');
    myNissan.color; // => 'red'

    constructor()内部のsuper()

    class MuscleCar extends Car {
      constructor(color, power) {
        this.power = power;
        super(color);
      }
    }
    
    // Does not work!
    const myCar = new MuscleCar(‘blue’,300HP’); // `ReferenceError`
    コンストラクション関数()でsuper()を呼び出すまでは使用できません.
    TDZは、親クラスのジェネレータを呼び出してインスタンスを初期化することを推奨します.親クラスの作成者を呼び出し、インスタンスを準備した後、子クラスで値を変更できます.
    class MuscleCar extends Car {
      constructor(color, power) {
        super(color);
        this.power = power;
      }
    }
    
    // Works!
    const myCar = new MuscleCar('blue', '300HP');
    myCar.power; // => '300HP'

    「デフォルト関数パラメータ」(Default Function Parameter)


    基本パラメータは、グローバルスキャンと関数スキャンの間の中間スキャンにあります.基本パラメータにはTDZ制限もあります.
    const a = 2;
    function square(a = a) {
      return a * a;
    }
    // Does not work!
    square(); // throws `ReferenceError`
    デフォルトのパラメータ a宣言の前に a = a 式の右側で使用します. aで参照エラーが発生しました.
    基本パラメータは、宣言と初期化の後に使用します.この場合 initなどの他の変数として宣言します.
    const init = 2;
    function square(a = init) {
      return a * a;
    }
    // Works!
    square(); // => 4

    var、function、import構文


    逆にvar,functionはTDZの影響を受けないと宣言している.これらは、現在のスキャンで転送されます.
    宣言前にvar変数にアクセスすると、Undefinedが取得されます.
    // Works, but don't do this!
    value; // => undefined
    var value;
    ただし、関数がどこで宣言されても呼び出されます.
    // Works!
    greet('World'); // => 'Hello, World!'
    function greet(who) {
      return `Hello, ${who}!`;
    }
    
    // Works!
    greet('Earth'); // => 'Hello, Earth!'
    関数宣言の前に呼び出すと、エラーは発生しません.なぜなら、呼び出し中のクロストークです.
    興味深いことに、importモジュールも転送されます.
    import { myFunction } from './myModule';
    import構文がエスケープになるので、JavaScriptファイルの先頭からエスケープモジュールをインポートすることをお勧めします.

    📌 TDZにおけるtypeof演算子の動作


    type of演算子は、変数が現在のscopeに宣言されているかどうかを確認するときに便利です.
    たとえば、  notDefined  変数は宣言されていません.この変数で  typeof  演算子を適用するとエラーが発生します.
    typeof notDefined; // => 'undefined'
    変数は宣言されていません.  typeof notDefined  評価はundefinedであった.
    しかし、TDZの変数では、  typeof  演算子の役割が異なります.次の場合にエラーが発生します.
    typeof variable; // throws `ReferenceError`
    let variable;

    📌 現在の範囲内のTDZ動作


    TDZは宣言の存在範囲内で変数に影響する.

    💡 整理する


    シースは、関数のすべての宣言を関数の有効範囲の上部にドラッグ&ドロップします.
    TDZはconst,let,classの影響を受ける.const、let、classでは、宣言前に変数を使用できません.
    逆にvar,function,importの宣言はTDZの影響を受けない.特にvar変数は宣言前にも使用可能であるため、予期せぬエラーが発生しないようにvar変数を使用することは避けたほうがよい.
    変数が最初に宣言されると、初期化に基づいてTDZが生成されます.特にlet,const,varの初期化点が異なる.varはデフォルトでundefinedに初期化された場合にJavaScriptコードを読み込むため、TDZでエラーは発生しません.
    これは、TDZを使用して、トランスコード、トランスコード、およびトランスコードがどのようにトランスコードに関連付けられているかを確認できる良い概念です.

    🐰 Reference

  • https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html
  • https://ui.toast.com/weekly-pick/ko_20191014
  • https://dmitripavlutin.com/javascript-variables-and-temporal-dead-zone/
  • https://velog.io/@wrfg12/ES6-Hoisting-Temporal-Dead-ZoneTDZ