JavaScript学習ノート-スコープ

7293 ワード

これらの知識点に詳しいと思います.ネット上には似たような文章がたくさんあります.間違いないです.これらの知識は全部「あなたが知らないJavaScript(上巻)」から得たものです.なぜもう一度書きますか?
一.スコープ
スコープは、変数がどこにあるか、どのように検索されるかを決定するためのルールです.
二.静的スコープ&ダイナミックスコープ
静的作用域は語法作用域とも呼ばれ、JavaScriptはこのような作用域を採用しています.これに対応するのは動的作用域です.それらの間の主な違いは、静的作用域はコードを書く時か定義する時に決められます.動的作用領域はコードを代行する時に決められます.
三.静的スコープ(品詞作用領域)
語法の作用域はその名前と同じで、語法の分析段階で決められたのです.JavaScriptコードは実行前にコンパイルが必要で、コンパイルは三つのステップに分けられます.
  • 品詞分析はコードを品詞ユニットに分解します.例えば、var a=1です.var、a、=、1、に分解されます.これらの語法ユニット
  • 文法解析では、語法ユニットをプログラムの文法構造を表すツリーに変換します.この木を「抽象文法ツリー」と呼びます.
  • コードは、抽象的な構文ツリーを実行可能なコードに変換する.
  • 例:
    var a = 1
    function foo() {
        var a = 2;
        bar();
    }
    
    function bar() {
        console.log(a);
    }
    
    foo();  // 1
    
    四.グローバルスコープ&関数スコープ&ブロックレベルスコープ
  • グローバルスコープ全体の変数はJavaScriptコードのどこにでもアクセスと修正できます.グローバルスコープの変数はグローバルオブジェクトの属性です.JavaScriptコードがブラウザの環境で実行されている場合、この全体のオブジェクトはwindowです.node.jsの場合、このグローバルオブジェクトはglobalです.例:
    var bar = 1;
    function foo() {
      console.log(bar);
    }
    foo();  // 1
    window.foo(); // 1
    window.bar;  // 1
    
    ここで注意したいのですが、letとconstを使ってグローバルスコープで変数を宣言すると、この変数は依然としてグローバル変数ですが、グローバルオブジェクトの属性ではなく、例
    let a = 1;
    window.a;  // undefined
    function foo() {
      console.log(a);
    }
    foo(); // 1
    
  • です.
  • 関数のスコープ関数のスコープ内の変数はこの関数でしかアクセスできません.関数以外ではアクセスおよび変更できません.閉ループによって関数外のスコープにアクセスし、関数のスコープ内の変数を変更することができます.例:
    function foo() {
      var bar = 1;
    }
    foo();
    console.log(bar); // Uncaught ReferenceError: bar is not defined
    
    注意:任意のキーワードを使用せずに直接変数を宣言すると、この変数は大域変数となります.例:
    function foo() {
        bar = 1
    }
    foo();
    console.log(bar); // 1
    
  • ブロック級作用領域
  • ブロックレベルのスコープはes 6の前に既に存在しています.try...catch.文、例:
    try{
      throw 1;
    } catch(a) {
      console.log(a);   // 1
    }
    console.log(a); // a is not defined
    
    es 6の構文では、letおよびconstキーで宣言される変数は、現在のコードブロックにしかアクセスできません.例:
    { let foo = 1; }
    { const bar = 2; }
    console.log(foo);  // foo is not defined
    console.log(bar);  // bar is not defined
    
    五.誤魔化す
    evalとwithを使うと法の作用領域を騙すことができますが、それを推奨しない理由は:
  • 厳格モードでは、withは禁止されています.
  • 遅い
  • evalは安全性の問題があります.
  • withは、いくつかの予想外の変数
  • を宣言する可能性がある.
    まず、詐欺の方法を見てみます.
    // eval
    function foo(str, a) {
        eval(str);
        console.log(a, b);
    }
    var b = 2;
    foo('var b = 3', 1);   // 1, 3,
    
    // with
    function bar() {
      var c = 2;
      with(window) {
         console.log(c);
      }
    }
    var c = 1;
    bar();   // 1
    
  • 試験性能
  • // eval
    let a = 0;
    let b = 0;
    
    function useEval() {
      console.time('useEval');
      for(let i = 0; i < 10000; i += 1) {
        a = eval(`${a} + ${i}`);
      }
      console.timeEnd('useEval');
    }
    
    function noEval() {
      console.time('noEval');
      for(let i = 0; i < 10000; i += 1) {
        b += i;
      }
      console.timeEnd('noEval');
    }
    
    noEval();
    useEval();
    
    node.js中:
    chromeブラウザコンソールにおいて:
    // with
    let obj = {
      a: 0,
      b: 1
    };
    function useWith() {
      console.time('useWith');
      with(obj) {
        for(let i = 0; i < 10000; i += 1) {
          a = a + i;
        }
      }
      console.timeEnd('useWith');
    }
    
    function noWith() {
      console.time('noWith');
      for(let i = 0; i < 10000; i += 1) {
        obj.b = obj.b + i;
      }
      console.timeEnd('noWith');
    }
    useWith();
    noWith();
    
    node.js中:
    chromeブラウザコンソールにおいて:
  • 補足説明
  • withについては、予想外の変数を宣言する可能性があるという点について、直接例を挙げて説明します.私の表現能力を使うと、ますます困惑するばかりです.
    let obj = {
      a: 1
    }
    with(obj) {
      a = 3
      b = 2
    }
    console.log(obj);  //  {a: 3}
    console.log(b);  // 2
    
    どうしてこのようにしてこの文章の12種類の使うべきでないJavascript文法を見に行くことができますか?
  • はwithとevalを使って遅くなる原因を説明しています.概括すると、エンジンはコンパイルする時に、作用域のルックアップを最適化して、コードの運行時に対応する作用域を迅速に見つけやすくします.しかし、withとevalのコードを使って、Withとevalのコードを使って、作用領域をどのように修正しますか?だから最適化しないしかないです.
  • 六.スコープとスコープの検索規則
    スコープ間は入れ子ができます.例えば、
    {
       let a = 1;
       {
         let b = 2;
       }
    }
    
    function foo() {
       let c = 3;
       function bar() {
         let d = 4;
       }
       bar();
       console.log(d);
    }
    
    関数fooを実行すると、エラー情報がd is not definedに報告されます.その理由は、作用領域の検索ルールです.
    作用領域を検索すると、ある変数が現在のスコープで検索されます.大域的なスコープが見つからない場合は、上(または外)へ検索されます.
    上記の例では、foo関数はまず自分の作用領域から検索し、見つからないなら外層の作用域を探します.つまり大域作用域を探して、大域作用域を見つけたら、まだないことが分かります.検索を停止して、異常を捨てればいいです.
    このルックアッププロセスによって形成される鎖は、ロールドメインチェーンと呼ばれる.
    転載先:https://juejin.im/post/5b90d18f6fb9a05ce873b874