JavaScriptソースコード解析:関数設計と変数宣言の最適化

(function(global, noValue) {
  global.myLib = function() {
    console.log('myLib関数が実行されました');
  };
})(window);

疑問点提起:1.自己呼び出し関数は外部のグローバル変数にアクセスできるのに、なぜwindowを引数として渡す必要があるのか?2.undefinedを引数として渡す意味は何か?

個人的な理解1:まず、実引数としてwindowを渡すことで、仮引数のglobalが外部のグローバル変数windowを指すことを明示しています。では、なぜ直接外部のwindowにアクセスせず、ローカル変数としてアクセスするのでしょうか?二つの利点があります。1.windowを毎回使用するたびに外部のグローバルwindowを探す必要がありますが、その検索プロセスはローカル変数にアクセスするよりも遅いです。2.ローカル変数を使用することは圧縮に有利で、仮引数のglobalを短い文字(例えばg)に書き換えることができ、ファイルサイズが小さくなります。

個人的な理解2:undefinedをなぜ仮引数として使用するのか(実際には実引数が渡されない場合はundefinedになります)。理由はIE678において、undefinedはキーワードではなく変数として変更できるためです。

// 厳格モードは不要です
var // メインのルートjQuery(document)への参照
    mainJQuery,
    // DOM準備完了時に使用されるDeferred
    readyQueue,
    // IE9サポート
    // `typeof xmlNode.method` の代わりに `xmlNode.method !== undefined` を使用するため
    core_undefinedType = typeof undefined,
    // window引数に応じて適切なdocumentを使用(サンドボックス環境)
    currentLocation = window.location,  // アドレス情報
    currentDocument = window.document,  // documentオブジェクト
    htmlElement = currentDocument.documentElement,  // htmlオブジェクト
    // jQueryが上書きされた場合のマッピング
    originalJQuery = window.jQuery,     // 外部のJQueryをoriginalJQueryに代入、競合を防ぐ
    // $が上書きされた場合のマッピング
    originalDollar = window.$,          // 外部の$をoriginalDollarに代入、競合を防ぐ
    // [[Class]] -> タイプペア
    typeMap = {},                      // $.type()で使用される型判定用オブジェクト
    // 削除されたデータキャッシュIDのリスト、再利用可能
    deletedCacheIds = [],               // データキャッシュに関連、2.0.3ではオブジェクト指向方式を採用
    libVersion = '2.0.3',
    // 一部のコアメソッドへの参照を保存
    arrayConcat = deletedCacheIds.concat,   
    arrayPush = deletedCacheIds.push,      
    arraySlice = deletedCacheIds.slice,    
    arrayIndexOf = deletedCacheIds.indexOf, 
    objectToString = typeMap.toString,    
    objectHasOwn = typeMap.hasOwnProperty, 
    stringTrim = libVersion.trim          

ソースコードでは、まずvarで変数を宣言してから後で値を代入する方法を使用しています。この方法には**圧縮に有利(式として書くと圧縮できないため)**という利点があります。変数は一文字で表現できます。もう一つの利点は、変数が何を意味するかが分かりやすく、メンテナンスが容易になることです。例えば、a+10(10が何を意味するか不明)と var length = 10; a+ length の違いです。

次に、core_undefinedType = typeof undefinedについて説明します。typeof undefinedの値は"undefined"なので、core_undefinedType = "undefined"となります。もしcore_undefinedTypeが"undefined"であれば、その変数は未定義です。window.a == undefinedでもチェックできますが、XmlNode.methodではサポートされていません。これは特殊なケースで、HTML環境では問題ありませんが、完全性のためにtypeof undefinedを使用しています。

なぜ直接core_undefinedType = "undefined"と書かないのか?これは圧縮に不利だからです。

    myFramework = function(selector, context) {
      // 実際にはinitコンストラクタを拡張したものがjQueryオブジェクト
      return new myFramework.fn.init(selector, context, mainJQuery);
    }

この部分では何が行われているのでしょうか? myFramework().css(), myFramework().width()などのメソッドにはすべてmyFramework()があります。myFramework()はmyFramework.fn.initのインスタンスを返しており、これはmyFramework.fn.initのプロトタイプにメソッドがあることを示しています。272行目にあるmyFramework.fn.init.prototype = myFramework.fn;により、myFrameworkのプロトタイプの参照がinitのプロトタイプに割り当てられています。これは参照型の代入であり、myFrameworkのプロトタイプが変更されると、initのプロトタイプもそれに伴って変更されます!【css(), width()などのメソッドはすべてmyFrameworkのプロトタイプで定義され、その後initのプロトタイプに参照されています】疑問点:なぜメソッドをjQueryプロトタイプ上に書くのか?なぜjQueryプロトタイプのメソッドをinitのプロトタイプで置き換えるのか?なぜinitはjQueryのプロトタイプ内に存在するのか?

タグ: javascript jQuery 最適化 プロトタイプ ソースコード解析

6月30日 16:04 投稿