スコープブースト

範囲

  • まず、スコープは、変数(識別子)をどこでどのように見つけるかを決定するための一連のルールです。検索の目的が変数に値を割り当てることである場合はLHSクエリが使用され、変数の値を取得することが目的である場合はRHSクエリが使用されます。代入演算子はLHSクエリを引き起こします。=関数を呼び出すときにパラメーターを渡す演算子または操作は、関連付けられたスコープでコピー操作を引き起こします。

コンパイルの原則

  1. JSはコンパイルされた言語です。言語をコンパイルする従来のプロセスでは、プログラム内のソースコードは、実行される前に3つのステップを経ます。これを総称して「コンパイル」と呼びます。
    • 単語のセグメンテーション/字句解析。このプロセスは、文字列を(プログラミング言語の場合)トークンと呼ばれる意味のあるコードブロックに分割します。例:var a = 2;は、var、a、=、2 ,;に分割されます。
    • 構文解析/文法分析。このプロセスは、字句単位のストリーム(配列)を、1つずつネストされたプログラム構文構造を表す要素で構成されるツリーに変換するもので、このツリーは「抽象構文ツリー」と呼ばれます。
    • コード生成。ASTを実行可能コードに変換するプロセスは、コード生成と呼ばれます。

スコープを理解する

  1. エンジンは必要に応じて変数を作成および保存でき、JavaScriptプログラム全体の最初から最後までのコンパイルと実行を担当します。
  2. コンパイラー、文法分析、コード生成、その他の汚い作業(コンパイルの原則)を担当
  3. スコープは、宣言されたすべての識別子(変数)で構成される一連のクエリを収集および維持し、これらの識別子に対する現在実行されているコードのアクセス権を決定する非常に厳密なルールのセットを実装します。
  4. 変数割り当て操作は2つのアクションを実行します。最初に、コンパイラーは現在のスコープで変数を宣言し(それがまだ宣言されていない場合)、次にランタイムエンジンがスコープ内で変数を探します。見つかった場合は、割り当てられます。

コンパイラー

  1. コンパイラは、コンパイルプロセスの2番目のステップでコードを生成しました。エンジンがコードを実行すると、ルックアップ変数aを使用して、宣言されているかどうかを判断します。検索プロセスはスコープによって調整されますが、エンジンはこのような検索を実行し、最終的な検索結果に影響を与えます。
  2. エンジンは、LHSの変数aを照会します。別のルックアップタイプRHS。
  3. LHS検索は、変数自体のコンテナーを見つけようとすることで、変数に割り当てることができます。これは、「割り当て操作のターゲットは誰ですか」と理解されます。RHSクエリと単純検索では、変数の値は同じであり、「誰が代入演算のソースであるか」と理解されます。
  4. JavaScriptエンジンは、最初にコードをコンパイルしてから実行します。このプロセス中に、var a = 2のような宣言は2つの別々のステップに分割されます。
    • まず、var aはそのスコープ内で新しい変数を宣言します。今回はコードが実行される前の最初です。
    • 次に、a = 2は変数aをクエリ(LHSクエリ)し、それに値を割り当てます。
  5. コンパイラーは、コードの生成と同時に、宣言と価値のある定義を処理できます。

スコープのネスト

  1. 高速関数または関数が別のブロックまたは関数にネストされると、スコープのネストが発生します。
  2. ネストされたスコープチェーンをトラバースするためのルール:エンジンは現在の実行スコープから変数の検索を開始し、それが見つからない場合は、1つのレベルを検索し続けます。最も外側のグローバルスコープに到達すると、検索プロセスは、見つかったかどうかに関係なく停止します。

異常な

  1. ネストされたすべてのスコープでRHSクエリが必要な変数を見つけられない場合、エンジンはReferenceErrer例外をスローします。
  2. エンジンがLHSクエリを実行するときに、ターゲット変数がトップレベル(グローバルスコープ)で見つからない場合、この名前の変数がグローバルスコープで作成され、エンジンに返されます(プログラムが厳格モード」。「厳密モード」では、エンジンはReferenceErrer例外をスローします。
  3. RHSクエリが変数を見つけたが、料金の関数型の値で関数呼び出しを行おうとしたり、nullまたは未定義の型の値の属性を参照したりするなど、変数の値に不当な操作を実行しようとした場合、どのエンジンTypeErrorがスローされます。
  4. ReferenceErrerはスコープの識別の失敗に関連していますが、TypeErrorはスコープの識別が成功したことを意味しますが、結果の操作は違法または不当です。

字句スコープ

「スコープ」は、エンジンが現在のスコープとネストされたサブスコープの識別子名に基づいて変数を検索する方法を管理するために使用される一連のルールとして定義されます。

字句ステージ

  1. ほとんどの標準言語コンパイラの最初の作業段階は、語彙と呼ばれます(語彙化とも呼ばれます)。字句化プロセスは、ソースコード内の文字をチェックし、それがステートフルな解析プロセスである場合は、セマンティクスという単語も提供します。
  2. 字句スコープは、字句ステージで定義されたスコープです。字句スコープは、コードを書くときに変数とブロックスコープをどこに書き込むかによって決まるため、字句アナライザがコードを処理するとき、スコープは変更されません(ほとんどの場合)。

探す

  1. スコープの検索は、最初に一致する識別子が見つかると停止します。同じ名前の識別子は、「シャドウイング効果」と呼ばれる、ネストされたスコープの複数のレイヤーで定義できます。シャドウ効果とは別に、スコープの恐怖は常に、それが実行されている最も内側のスコープから始まり、最初に一致する識別子に直接遭遇するまで、段階的に外側または上方に進みます。
  2. 関数がどこで呼び出されても、またどのように呼び出されても、その字句スコープは関数が宣言されている位置によってのみ決定されます。

虚偽の語彙

  1. JavaScriptには、実行時に字句スコープを「変更」する(またはだます)ためのメカニズムが2つあります。ただし、レキシカルスコープをだますと、パフォーマンスが低下し、エンジンはコンパイル時に検索を最適化するために使用できません。これは、エンジンがそのような最適化が無効であると慎重にしか判断できないためです。

  2. JavaScriptのeval(...)関数は、文字列のボックスをパラメーターとして受け入れることができ、その中身は、作成時にプログラムのこの位置に存在するように見えるコードです。eval(...)の後にコードを実行すると、エンジンは前のコードが動的なフォームに挿入されていることを「認識」または「ケア」せず、字句スコープ環境が変更されます。エンジンはレキシカルスコープのルックアップのみを通常どおり実行します。

    function foo(str,a){
        eval(str);//欺骗console.log(a,b);
     }
    val b = 2; 
    foo("var b = 3;",1);//1,3
    
  3. eval(...)は通常、動的に作成されたコードを実行するために使用されます。

  1. withは、通常、同じオブジェクト内の複数の属性を繰り返し参照するショートカットとして使用されます。オブジェクトを繰り返し参照する必要はありません。
  2. withは、属性のないオブジェクトまたは複数のオブジェクトが完全に分離された字句スコープとして扱われるため、このオブジェクトの属性もこのスコープで定義された字句識別子として扱われます。
  3. eval(...)関数が1つ以上の宣言を含むコードを受け入れる場合、eval(...)関数はそれが含まれているレキシカルスコープを変更し、withステートメントは実際に、渡されたオブジェクトに基づいてまったく新しいレキシカルスコープを作成します。
  4. eval(...)とwithは、strictモードの影響を受けます(制限されます)。withは完全に禁止されており、コア機能を保持することを前提に、eval(...)の導入または安全でない使用も禁止されています。

関数スコープと高速スコープ

関数スコープ

関数スコープの意味は、この関数に属するすべての接続梁が、関数全体のスコープ内で使用および再利用できることを意味します(実際、ネストされたスコープでも使用できます)。この設計は非常に便利で、JavaScript変数を十分に活用して、必要に応じて値タイプの「動的」特性を変更できます。

内部実装を非表示にする

  1. コードの任意の部分を選択し、それを関数宣言でラップすると、実際にはコードが非表示になります。
  2. 実際の結果として、このコードフラグメントの周りにスコープバブルが作成されます。つまり、このコード内の宣言(変数、関数)豆乳は、前のコードではなく、この新しい革新的なパッケージ関数のスコープにバインドされます。スコープ内。つまり、変数と関数を関数のスコープでラップし、このスコープを使用してそれらを「非表示」にすることができます。
  3. 「隠された」変数と関数のほとんどは、最小権限の原則から適用されます。これは、最小認可または最小公開の原則とも呼ばれます。

紛争回避

「非表示」スコープ内の変数と関数のもう1つの利点は、同じ名前の識別子間の競合を回避できることです。2つの識別子は同じ名前であるが、用途が異なり、意図せずに名前の競合を引き起こす可能性があります。競合により、変数の値が誤って上書きされる可能性があります。

関数スコープ

  1. 関数の宣言と式を区別する最も簡単な方法は、関数のキーワードが宣言内のどこにあるかを確認することです(コード行だけでなく、宣言全体での位置)。functionが宣言の最初の単語である場合、それは関数宣言です。それ以外の場合は、関数式です。
  2. 関数宣言と関数式の最も重要な違いは、それらの名前識別子が結び付けられる場所です。(関数foo(){...})関数式は、fooは...で表される位置でのみアクセスでき、外部スコープではないことを意味します。foo変数名はそれ自体が隠されており、外部スコープを不必要に汚染しないと考えています。

匿名および名前付き

setTimeout(function(){
        console.log('I waited');
 },100);
  1. function()...には名前識別子がないため、これは無名関数式と呼ばれます。
  2. 無名関数の欠点:
    • 無名関数はスタックトレースに意味のある関数名を表示しないため、デバッグが困難になります。
    • 関数名がない場合、関数がそれ自体を参照する必要がある場合は、期限切れのarguments.calles参照のみを使用できます。
    • 無名関数は、コードの読みやすさ/理解しやすさにとって重要な関数名を省略します。わかりやすい名前を付けると、コードが一目瞭然になります。
  3. 常に関数式に名前を付ける:関数の後に名前を追加します()

関数式をすぐに実行する

  1. 関数は()のペアで囲まれているので式になり、最後に(function foo(){...})()のように別の()を追加することで、関数をすぐに実行できます。最初の関数が式になり、2番目の()がこの関数を実行します。

  2. IIFE:関数式の即時実行を表します。

  3. 従来のIIFEと比較して、もう1つの改善された形式があります:(関数(){…}())。これら2つの正式な関数は一貫しています。

  4. IIFEのもう1つの非常に一般的な高度な使用法は、それらを関数呼び出しとして扱い、パラメーターを渡すことです。

     var a = 2;
     (function IIFE(global){
         var a = 3;
         console.log(a);//3
         console.log(global.a);//2
     })(window);
     console.log(a);
    

このパターンのもう1つのアプリケーションシナリオは、未定義の識別子のデフォルト値がエラーによって上書きされることによって引き起こされる例外を解決することです(一般的ではありません)。undefinedという名前のパラメーターについて説明しますが、コードブロック内の未定義の識別子の値が実際に未定義であることを保証するために、対応する位置に値は渡されません。
5. IIFEのもう1つの用途は、コードの実行順序を逆にして、必要な関数を2番目に配置し、IIFEの実行後にそれらをパラメーターとして渡すことです。

ブロックスコープ

  1. widthは、ブロックスコープ(ブロックスコープの形式)の例でもあります。withを持つオブジェクトから作成されたスコープは、withステートメントでのみ有効で、外部スコープでは無効です。

  2. JavaScriptのES3仕様では、try / catch句がブロックスコープを作成し、宣言された変数がキャッチ内でのみ有効であることが規定されています。

     try{
         undifined();//执行一个非法操作来强制制造一个异常
     }
     catch(err){
         console.log(err);//能够正常执行!
     }
     console.log(err);//ReferenceError
    
  3. 同じスコープ内の2つ以上のcatch句が同じ識別子名エラー変数を使用するときに静的検査ユニオンエラーの不要な警告を回避するために、多くの開発者はキャッチパラメータにerr1、err2などの名前を付けます。 。一部の開発者は、静的チェックツールをシャットダウンして、重複する変数名をチェックします。

させる

  1. letキーワードは、変数を任意のスコープ(通常は内部の{…})にバインドできます。つまり、letは、letによって宣言された変数が含まれるブロックスコープを暗黙的にハイジャックします。

  2. letを使用して既存のブロックスコープに変数をアタッチする動作は暗黙的です。表示されたコードは、暗黙的またはいくつかのデリケートですが不明確なコードが原因です。次に表示コードを示します。

     var foo = true;
     if(foo){
         {//显示代码块
             let bar = foo * 2;bar = something(bar);
             console.log(bar);
         }
     }
    
  3. 宣言が有効である限り、宣言の任意の場所で{...}ブラケットを使用して、バインドするブロックを作成できます。この例では、ブロックはifステートメント内に明示的に作成されます。リファクタリングが必要な場合、外部のifステートメントの位置とセマンティクスに影響を与えることなく、ブロック全体を簡単に移動できます。

const

ES6ではconstも導入されました。これは、ブロックスコープ変数の作成にも使用できますが、その値は固定(定数)です。価値のある操作を変更しようとすると、エラーが発生します。

宣伝する

コンパイラは再びストライキします

  1. コンパイルフェーズの仕事の一部は、すべての宣言を見つけて適切なスコープに関連付けることです。
    a = 2; var a; console.log(a); // 2を出力します
  2. var a = 2;は実際にはvar a;と見なされ、a = 2;最初の定義宣言はコンパイル段階で行われます。2番目の代入ステートメントは実行のために残されます。つまり、最初に宣言してから値を割り当てます。
  3. つまり、スコープ内の宣言がどこにあっても、コード自体が実行される前に処理されます。このプロセスは、すべての宣言(変数と関数)がそれぞれのスコープの最上位に移動されるため、視覚的に想像できます。このプロセスは、昇格と呼ばれます。
    4.各スコープが昇格されることに注意してください。
    5.宣言自体は昇格され、関数式の代入を含む代入演算は昇格されません。

最初に機能

1.関数と変数の両方の宣言が昇格されます。ただし、関数が最初に昇格し、次に変数が昇格する詳細(この詳細は、複数の「重複」宣言を含むコードに表示される場合があります)があることに注意してください。

    foo();//1 var foo; 
    function foo(){
        console.log(1);
    }
    foo = function(){
        console.log(2);
    };//会输出1而不是2
  1. 繰り返されるvar宣言は無視されますが、背面に表示される関数宣言は前の関数宣言をカバーしています。

この記事の定義と例は、以下から取得されます。

  • 「あなたが知らなかったJavaScript」
元の記事を17件公開しました 賞賛されました0 訪問771

おすすめ

転載: blog.csdn.net/CandiceYu/article/details/89136613
おすすめ