[モダンJavaScript Deep Dive]-14グローバル変数の問題


14.1変数のライフサイクル


14.1.1地域変数のライフサイクル


変数には生成と消失のライフサイクルがあります.
グローバル変数のライフサイクルは、アプリケーションのライフサイクルと同じです.
ゾーン変数のライフサイクルは、関数のライフサイクルと一致します.
前の4.4節「変数宣言の実行時間と変数反発」では、宣言がどこにあるかにかかわらず、変数宣言が最初に実行されます.しかし、厳密には、これはグローバル変数に限られる.
変数のライフサイクルは、メモリ領域から解放され、使用可能なメモリプールに戻る時間です.
変数は、自分が登録したスキャンプログラムが破棄されるまで有効です.割り当てられたメモリ領域が誰にも参照されなくなると、ゴミ収集器によって解放され、使用可能なメモリプールに戻されます.
この点スコフも同じだ.スコフを参照する人がいれば、スコフは消えずに生きていく.
前の例を見てみましょう
var x = 'global';

function foo(){
	console.log(x); // (1)
    var x = 'local';
}

foo();
console.log(x); // (2)
foo関数内部で宣言された領域変数xは(1)点で未定義に初期化されている.したがって,(1)グローバル変数ではなく領域変数xを参照して値を出力する.
このように、オフセットはスキャン単位で動作し、グローバル変数と領域変数のオフセットを比較すると、以下のようになります.
  • グローバル変数のハウスティンの動作は、グローバル変数の宣言がグローバルScopeの前列に上昇したように.
  • 地域変数のハウスティンの動作は、地域変数の宣言が地域スコフのリード地位に昇格したようにしている.
  • つまり、HOISTINGはJavaScript固有の特徴であり、変数宣言がscopeのフロントエンドに昇格したように動作する.

    14.1.2グローバル変数のライフサイクル


    関数とは異なり、グローバルコードは明示的な呼び出しなしで実行されます.すなわち,グローバルコードは特にエントリポイントがなく,コードがロードされるとすぐに解釈され実行される.また、戻り文は使用できないため、最後の文が実行され、実行する文がなくなった場合に終了します.
    varキーワードとして宣言されたグローバル変数は、グローバルオブジェクトのpropertyとなります.
    グローバルオブジェクト(グローバルオブジェクト)とは?
  • グローバルオブジェクトは、コードが実行される前にJavaScriptエンジンによって任意のオブジェクトより先に作成された特殊なオブジェクトです.
  • は、クライアント側環境においてウィンドウを表し、サーバ側環境においてグローバルオブジェクトを表す.
  • 環境によっては、グローバルオブジェクトを指す様々な識別子(window、self、this、frame、global)が存在するが、ES 11からglobalThisに統一される.
  • 전역객체와 표준 빌트인 객체에 대해서는 21장 "빌트인 객체"에서 자세히 살표보도록 한다.
    ブラウザ環境では、グローバルオブジェクトはwindowなので、ブラウザ環境でvarキーワードとして宣言されるグローバル変数は、グローバルオブジェクトwindowのpropertyです.
    グローバルオブジェクトウィンドウは、Webページを閉じる前に有効です.したがって、ブラウザ環境でvarキーワードとして宣言されたグローバル変数は、Webページを閉じる前に有効です.
    すなわち、varキーワードで宣言されるグローバル変数のライフサイクルは、グローバルオブジェクトのライフサイクルと一致する.

    14.2グローバル変数の問題

  • 暗跡結合
  • グローバル変数は、すべてのコードがグローバル変数を参照および変更できるデフォルトの欠陥です.変数の有効範囲が大きいほど可読性が悪くなり,不用意に状態を変える危険性が高い.
  • 長寿命期間
  • ライフサイクルが長いため、グローバル変数の状態が変化する時間と機会が多い.変数名の重複による再割り当ても可能です.
  • スコフ鎖では,終点に
  • が存在する.
    グローバル変数はスキャンチェーン上の終点に存在し、変数を検索すると最後に検索されます.すなわち,グローバル変数の探索速度が最も遅い.
  • 名前空間汚染
  • JavaScriptの最大の問題の1つは、ファイルが別々であってもグローバルスキャンを共有することです.したがって、ファイルに同じ名前のグローバル変数またはグローバル関数が存在する場合、予想外の結果が発生する可能性があります.

    14.3グローバル変数を無効にする方法


    上記の問題を理由に、グローバル変数の使用をできるだけ抑制し、地域変数を使用する必要があります.また,変数のスキャンは狭いほどよい.
    グローバル変数の使用を抑制する方法は次のとおりです.

    14.3.1即時実行関数


    関数定義と同時に呼び出されるインスタント実行関数は1回のみ呼び出されます.次の例に示すように、すべてのコードが即時実行関数に囲まれている場合、すべての変数は即時実行関数の領域変数になります.
    (function () {
     var foo = 10;
    }());
    
    console.log(foo); // ReferenceError: foo is not defined

    14.3.2名前空間オブジェクト


    方法は、グローバルにネーミングスペースの役割を果たすオブジェクトを作成し、グローバル変数として使用したい変数をpropertyに追加することです.
    var = {}; //전역 네임스페이스 객체
    
    MYAPP.name = 'AN';
    
    console.log(MYAPP.name); //AN
    ネーミングスペースを分離すると識別子の競合を防止できますが、ネーミングスペースオブジェクト自体がグローバル変数に割り当てられるため、あまり役に立ちません.

    14.3.3モジュールモード


    モジュールモードはクラスを模倣し,関連する変数と関数を集合させ,即時実行関数で包み,モジュールを形成する.モジュールモードはJavaScriptの強力な機能モジュールに基づいています.モジュールモードの特徴は,グローバル変数の2日前だけでなくカプセル化も可能であることである.
    モジュールモードについては、モジュールについて説明する必要があります.これは、24章の「モジュール」で詳しく説明します.現在の段階では、「シャーシ」という機能がグローバル変数を抑制できることに注意します.
    パッケージとは,オブジェクトの状態を表すプログラムと操作可能な動作方法を組み合わせたものである.カプセル化は、情報非表示と呼ばれるオブジェクトを非表示にするための特定のプログラムまたは方法です.
    オブジェクト向けのプログラミング言語の多くは、公開範囲を限定するために、公開、プライベート、保護されたアクセス制限者などを使用することができます.ただし、JavaScriptではアクセス制限はありません.
    モジュールモードは,グローバルネーミング空間汚染を防止する機能だけでなく,限られているが,情報隠蔽を実現するために用いられる.
    var Counter = (function () {
    
    	var num = 0;
        
        return {
        	increase() {
            	return ++num;
            },
            decrease() {
            	return --num;
            }
        };
    }());
    
    console.log(Counter.num); // undefined
    console.log(Counter.increase()); // 1
    console.log(Counter.increase()); // 2
    console.log(Counter.decrease()); // 1
    console.log(Counter.increase()); // 2
    上記の例では、返されるオブジェクトのPropertyは共通メンバーであり、numなどの外部からアクセスできない変数や関数はプライベートメンバーです.

    14.3.4 ES 6モジュール


    ES 6モジュールは、ファイル自体の独立したモジュールスキャンを提供する.
    ES 6モジュールを使用すると、グローバル変数は使用できなくなります.したがって、モジュールでvarキーワードとして宣言された変数はグローバル変数ではなく、windowオブジェクトのpropertyではありません.
    <script type="module" scr="A.mjs"></script>
    <script type="module" scr="B.mjs"></script>
    例に示すように、type=「module」コメントを追加すると、ロードされたファイルがモジュールとして実行され、拡張子はmjsを推奨します.
    ES 6モジュールはIEを含む旧式ブラウザでは機能せず、利用可能であっても変換またはバンドルが必要であるため、通常Webpackなどのモジュールバンドルパッケージが使用される.
    モジュールやWebpackなどのモジュールバンドルパッケージの導入方法は,48章「モジュール」と49章「BarelとWebpackを用いてES 6+/ES.NEXT開発環境を構築する」で議論する.