happyjam

happyjam

JSコンパイルの原理

JS コンパイル原理#

var name = "rose";

上記のコードは、JS では次のように表示されます:

var name; // コンパイルフェーズで処理されます
name = "rose"; // 実行フェーズで処理されます

JS コンパイルは主に 2 つのフェーズに分かれます:コンパイルフェーズと実行フェーズ

コンパイルフェーズ#

このフェーズでは、コンパイラが主役です。

  • JS はスコープを探し、変数nameが存在するかどうかを確認します。
    • もし既に存在していれば、何もせずにvar nameの宣言を無視して、次のコンパイルに進みます。
    • 存在しなければ、現在のスコープに新しいname変数を追加します。
  • コンパイラはエンジンが実行に必要なコードを生成し、プログラムは実行フェーズに入ります。

実行フェーズ#

このフェーズでは、JS エンジンが主役です。

  • JS エンジンは実行時に現在のスコープを探し、nameという変数が存在するかどうかを確認します。
    • 存在すれば、値を代入します。
    • 存在しなければ、現在のスコープには存在しないことを示します。その後、親スコープを見てnameが存在するかどうかを確認します。存在しなければ、さらに上のスコープを探します。
    • 最終的に見つからなければ、エラーが発生します。

      スコープがスコープに入れ子になっていることを意味するスコープチェーン。

スコープ#

変数の基本的な機能は、変数内の値を格納し、その変数にアクセスおよび変更することができることです。そして、変数の格納とアクセスのルールスコープです。

グローバルスコープ#

関数の外部またはコードブロックの外部のトップレベルスコープはグローバルスコープであり、その中の変数はグローバル変数です。

var name = "rose"; // グローバルスコープ

function showName() {
  // 関数スコープ
  console.log(name);
}
{
  name = "test"; // ブロックスコープ
}
showName(); //test

グローバル変数は、グローバルスコープ、関数スコープ、ブロックスコープのいずれでも正常にアクセスできることがわかります。

関数スコープ#

関数内部のスコープは関数スコープです。

function showName() {
  var name = "jack"; // 関数スコープ
}
showName(); //メソッド呼び出し
{
  console.log(name); //ブロックスコープ、Uncaught ReferenceError: name is not defined
}
console.log(name); //グローバルスコープ、Uncaught ReferenceError: name is not defined

関数内部の変数は、グローバルスコープおよびブロックスコープではアクセスできず、関数内部でのみアクセスできるため、関数内部の変数はローカル変数とも呼ばれます。

ブロックスコープ#

ES6で新しく導入されたletおよびconstキーワードは、ブロックスコープを持っています。ブロックスコープは、そのコードブロック内でのみ有効であり、中括弧{}で囲まれている場合、中括弧はコードブロックを表します。constで宣言された変数もローカル変数と呼ばれます。

 {
   let name='rose';
 }

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

 function showName{
   console.log(name);
 }

 showName();    //Uncaught ReferenceError: name is not defined

ブロックスコープ内の変数は、コードブロックの外部からアクセスできなくなります。

スコープチェーン#

スコープとスコープのネストにより、スコープチェーンが生まれます。スコープチェーンの検索は外側に向かって行われます。

変数の巻き上げ#

name = "rose";
console.log(name); //rose
var name;

このコードは正常に実行され、エラーは発生しません。
JS の視点では、実際のコードは次のようになります:

var name;
name = "rose";
console.log(name); // rose

letおよびconstのコード:

name = "rose";
console.log(name); //Uncaught ReferenceError: Cannot access 'name' before initialization
let name;

letconst変数の巻き上げを禁止します。constは宣言後に値を設定する必要があります。

let、const、var の違い#

  1. ブロックスコープ:ブロックスコープは{}で囲まれた範囲で有効であり、letおよびconstはブロックスコープを持ち、varにはブロックスコープはありません。

ブロックスコープは、ES5の 2 つの問題を解決します:

  • 内側の変数が外側の変数を上書きする可能性がある
  • カウントに使用されるループ変数がグローバル変数に漏れる可能性がある
  1. 変数の巻き上げvarは変数の巻き上げがありますが、letおよびconstには変数の巻き上げはありません。つまり、変数は宣言後にのみ使用できます。それ以外の場合はエラーが発生します。
  2. グローバルへのプロパティの追加:ブラウザのグローバルオブジェクトは window であり、Node のグローバル変数は global です。varで宣言された変数はグローバル変数として追加され、その変数はグローバルオブジェクトのプロパティとして追加されますが、letおよびconstは追加されません。
  3. 重複の宣言varで変数を宣言する場合、同じスコープ内で変数を重複して宣言することができます。後で宣言された変数が前に宣言された変数を上書きします。一方、letおよびconstでは、同じスコープ内で変数を重複して宣言することはできません。
  4. 一時的な死区letconstキーワードを使用して変数を宣言する場合、その変数は使用できません。これは、構文的には一時的な死区と呼ばれます。

varで宣言された変数は一時的な死区が存在しません。

  1. 初期値の設定:変数を宣言する際、varおよびletは初期値を設定する必要はありません。一方、constで変数を宣言する場合は初期値を設定する必要があります。
  2. ポインタの指向letおよびconstは、ES6 で導入された変数の作成に使用される構文です。letで作成された変数はポインタの指向を変更できます(再代入できます)。一方、constで宣言された変数はポインタの指向を変更することはできません(再代入はできません)。

一時的な死区#

var name = "rose";

{
  name = "bob";
  let name; //Uncaught ReferenceError: Cannot access 'name' before initialization
}

もしブロック内に let や const が存在する場合、そのブロック内で宣言された変数 name には一時的な死区の制限が追加されます。
JS は明確に name が現在のコードブロック内で let で宣言されていることを認識しているため、この変数 name には一時的な死区の制限が追加され、外に出てくることはありません。
したがって、上記のlet name;を削除しても、プログラムは正常に実行され、name の値も正常に blob に変更されます。これは、スコープチェーンのルールに従って、外に出てくることができるからです。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。