最初からフレームを書く(二):フレームを育む種_上

8175 ワード

今日はフレームワークの最も基本的な部分:シードモジュールについてお話しします.
 
この語は@司徒正美が彼の《JavaScriptフレームワーク設計》の本の中で提出した1つの語で、意味は:このモジュールは1本の大木の種のようで、そのすべてのモジュール、方法など、すべてこの種子モジュールの中に根ざして、それは他のモジュールを包容して、他のモジュールの間のつながりを緊密にして、しかもユーザーにもっと便利にモジュール、方法を呼び出すことができます.
 
シードモジュールは安定性、拡張性が高く、よく使われるなどの原則を堅持する必要があります.では、作成を始めましょう.
 
@司徒正美の本では、シードモジュールには、オブジェクト拡張、配列化、タイプ判定、簡単なイベントバインドとアンインストール、衝突処理なし、モジュールロードとdomReadyという機能が必要だと述べています.
 
単純なフレームワークを完了するだけなので、これらのすべての機能を含める必要はありません.単純な機能を含めるだけでいいです.オブジェクトの拡張、モジュールのロード、衝突のない処理です.うん、多分これだけで十分だ.その他の機能は、興味があれば『JavaScriptフレームワークデザイン』を購入して自分でめくることができます.
 
この部分は少し長いので、3つの部分に分けて展開します.
 
では、私たちのシードモジュールの作成を始めます.
 
1.ネーミングスペース
ネーミングスペースとは何ですか?いくつか例を挙げてみましょう
たとえば、多くのフレームワークでは、追加された$記号、avalonjsのavalon、vuejsのVueなどが愛用されています.これらはモジュールのネーミングスペースで、windowオブジェクト(JQquey、avalonjsなど)にバインドされているものもあれば、windowオブジェクト(vuejsなど)にバインドされていないものもあります.使用する場合はnew Vueで新しいインスタンス呼び出しを作成します).しかし、彼らには共通の特徴があり、ネーミングスペースにはフレームワークのすべてのモジュールと方法が含まれており、使用者は$しか必要としない.XXXはこのようにモジュールを直接呼び出すことができます.
ネーミングスペースの使用の利点は明らかです.まず、グローバルな役割ドメインの汚染を防止し、ユーザーに出口を1つだけ漏らすことで、ユーザーが内部のモジュールをより容易に呼び出すことができます.
しかし、prototypejsのようなフレームワークには1つ以上のネーミングスペースがあることに注意してください.このような目的はたくさんありますが、私たちのフレームワークにはネーミングスペースが1つしか必要ないので、今日はこの話題を展開しません.
 
ネーミングスペースは出入り口に相当し、ユーザーはネーミングスペースを使用してフレームにどのモジュールが必要かを教え、フレームは内部でモジュールを呼び出した後、結果をユーザーに返します.
 
シンプルなネーミングスペースの実現は、
if(window !== 'undefined'){ //     window   undefined

	window.$ = {}; //        
	window.$.css = {} //     ...
	window.$.animate = {} //     ...
	//.....
	
}

  
これにより、ネーミングスペースに各種のモジュールと方法を登録することができ、使用する際に$しか必要ない.XXXはこのように使えばいいです.
しかし、それだけでは、明らかに安全ではありません.
まず、多くのフレームワークが$記号に涎を垂らしている(確かに使いやすい)と言ったので、私たちのフレームワークの前に他のフレームワークをロードすると、$符ネーミングスペースが占有される場合があります.私たちが単独で名前をつけたネーミングスペース(例えば私が自分のフレームをAHjsと呼ぶ)でも、ネーミングスペースの重複が発生する可能性があり、このような場合、後にロードされたフレームが先にロードされたフレームのネーミングスペースをカバーする場合があります.これは明らかに私たちが望んでいる結果ではありません.
では、どのようにして2つのフレームワークを同時に残すことができますか?よく知られているように、JQqueryは現在、ほとんど(ほとんど取り除くことができる)最もよく使われているフロントエンドフレームワークであり、そのネーミングスペースは$記号であり、JQQueryの発展初期には、当時のフロントエンドフレームワーク分野の覇者はprototypejsであり、そのネーミングスペースも$記号であり、JQueryは自身の発展のためにマルチライブラリ共存メカニズムを導入した.マルチライブラリ共存メカニズムは、現在のフロントエンドフレームワークの標準化されています.
JQueryがどうやってやったか見てみましょう.
var _jQuery = window.jQuery , _$ = window.$ //                  。

function onConflict(deep){

	window.$ = _$ //         ,        、          。

	if(deep){ //           ( jQuery)

		window.jQuery = _jQuery; //     

	};

	return jQuery;

};

  
このようにして、フレーム間の競合の問題を解決するために、フレームワークにネーミングスペースを再定義します.
もちろん、注意深い読者は、この方法には、クラスライブラリ、フレームワークがhtmlに最後にロードされなければならないという条件があることを発見する必要があります.そうしないと、他のフレームワークのネーミングスペースを保存する役割を果たすことができません.(最初のロードの場合、window.$はまだ未定の状態であり、undefinedのみが保存されます).
 
OK、衝突処理が解決しました.今、ネーミングスペースも改善します.
!function(global , target){ //    ,      、    

	if(typeof global !== 'undefined'){ //          

		global.Cvm = global.$ = target(); //                  

	}else{

		throw new Error("Cvm requires a window with a document") //         

	}

}(typeof window !== 'undefined' ? window : this , function(){})  
//     ,window     ,   window      ,  this(    window)

  
OK、ここまで来て、私たちは名前空間をwindowオブジェクトにバインドすることに成功しました.工場の方法については、他のモジュールを作成して返します.これは次の話題を引き出します.工場のモードです.
 
2.フレームワーク構築に最適なモデル:工場モデル
工場モデルは、その名の通り、工場のように、ユーザーが注文し、工場に必要なモジュール、機能を教えます.工場は注文を受けた後、ユーザーが必要とするモジュールを組み立てて、最後にユーザーに返します.
それは私たちのコードをもっと工業化して規範化させて、たとえ大規模なフレームワークであっても、すぐに万行のコード量を達成して、構造がはっきりしていて、メンテナンスが便利です.
工場モデルは複雑に聞こえますが、実現は簡単です.
function product(){ //       
	return {
		name:"sneakers",
		state:"new",
		size:"44"
	}
}

function sneakersFactory() {} //        

sneakersFactory.prototype.product = product; //     
sneakersFactory.prototype.createSneakers = function(options){

	if(options.sneakersType === "sneakers"){ //         
		this.product = product; //    sneakers
	}else{
		return options.sneakersType + 'is not defined'; //  ,            ...
	}

	return new this.product( options ); //        

}

var sneakersFactory = new sneakersFactory();
var sneakers = sneakersFactory.createSneakers({
            sneakersType: "sneakers",
            state: "new",
            size: 44 
        }
    );

console.log(sneakers) //        

  
これにより、簡単な工場が実現され、私たちのすべてのモジュールが工場の生産環境に登録され、ユーザーが必要とするときに、モジュールを生産して彼の手に届きます.このような方法で私たちの枠組みを秩序正しく構築し、私たちの枠組みをより工業化させます.
 
次に、ファクトリモードをシードモジュールにバインドします.
!function(global , target){

	if(typeof global !== 'undefined'){

		global.Cvm = global.$ = target();

	}else{

		throw new Error("Cvm requires a window with a document")

	}

}(typeof window !== 'undefined'? window : this , function(){ //       

	return (function(modules){//                  ,        

		

	})([])//         

})

  
はい、私たちの工場方法はシードモジュールにバインドすることに成功しました.しかし、他の機能モジュールの作成を開始するまでは、まだ距離があります.次に下を見てみましょう.
 
今私たちは工場を持っていますが、この工場は空いている工場です.
はい、簡単に言えば労働者がいません.ああ、製品にかかわらず、私たちはまず労働者がいてから製品を生産しなければならないのではないでしょうか.本当の工場を想像してみてください.販売を担当するルートがあり、倉庫管理があり、出荷を担当し、労働者が生産を担当し、あなたが持っている製品を保存するために大きな倉庫が必要です.あなたはあのボスです(考えてみればまだ持っていますね~).
so、私たちはまず私たちの工場のためにいくつかの人を募集する必要があります.
採用リストを見てみましょう.ルート(注文を受け入れる責任)、倉庫管理(貨物の輸送責任)、労働者(製品の生産責任).それ以外に倉庫を設置する必要があります(既存の製品を格納します)
 
これらを解決するために、モジュールのロードメカニズムが必要です.
 
3.モジュールのロードメカニズム
現在、commonjs、requirejsなど、モジュール管理に専念するフレームワークが市販されています.およびそれによって誘導されたAMD仕様.
AMD仕様とは何ですか? 
AMDの全称はAsynchronous Module Definition非同期モジュールロードメカニズムである.
近年の先端分野の大きな突破と言える.具体的な私たちは詳しく展開しないので、興味のある友达は自分で資料を調べることができます.
AMD仕様がどのように動作しているかを知るだけでいいです.
 
初めてAMD仕様に触れた友人は、驚くかもしれません.非同期モジュールのロードメカニズムであるためです.最も重要なのは非同期の2つの字で、jsは非同期処理に関連して、コールバック関数を使って処理するしかありません.これはJS分野で有名なcallback hell(コールバック地獄)を招いた.はい、確かに頭が痛いです.多くの関数のコールバックが止まらないネストは関数と関数の結合度を増加させ、後期のメンテナンスと安定性に大きな衝撃を与えます.
 
しかし、実際にAMD仕様に触れてみると、実際には想像していたほど怖くなく、コールバック関数が加わっても、以前よりずっとよくなっています.
また、AMD仕様では、モジュールの書き込みロードメカニズムが規定されており、モジュールをより簡単に使用し、モジュール間の結合状態を低減することができます.
では、あまり言わないで、まずAMD規範をどのように書く必要があるかを見てみましょう.
define(id?, dependencies?, factory);
これはAMD仕様で作成された作成モジュールAPIで、3つのパラメータがあります.それぞれ:
1.モジュール名は省略可能
2.モジュールに必要な依存は省略可能
3.モジュールの実現に必要
依存は省略できます.これはよく理解されています.このモジュールは追加の依存を必要とせずに独立して動作するか、いっそこのモジュールは他のモジュールに依存するために使用される可能性があります.
ただしモジュール名は省略できますか?これは...実際、AMD仕様は、このような匿名モジュールの定義方法を推奨している.モジュールにロードされたAPI:requireでは,信頼性の高い匿名モジュールクエリーメカニズムが策定されているので,匿名モジュール依存の心配は全くない.
 
はい、具体的には話をしません.さもないと、今晩パソコンの前に座ってタイプするかもしれません.の
最も基本的なことは、モジュールの定義と使用、残りは後で展開することだけです.
また,便宜上,ユーザが匿名モジュールを定義することは許されない.Require匿名モジュールのクエリーメカニズムに関連するため、展開して話をすると大きな幅になるため、ここではユーザーが名前付きモジュールを定義することしかできません.
 
まず、ユーザーや開発者に勝手に自分のモジュールを定義させることはできません.もし私がモジュールaを定義した後、他の人が同じ名前のモジュールaを定義したら、モジュールオーバーライドが発生します.そこで,ユーザ定義の際に,ユーザが必要とするモジュールが既に存在する場合,定義したモジュールをユーザに直接返すと判断する.
このためには、定義済みのモジュールを格納する倉庫が必要です.
var modules = {};

function define(name , dependencies , fn){ //   、  、  

	if(!modules[name]){ //            

		var module = { //       ,         
			name:name,
			dependencies:dependencies,
			fn:fn
		} //    、  、        

		modules[name] = module; //            。

	};

	return modules[name] //              ,                

}

  
これにより、モジュールの重複が既存のモジュールを上書きすることを恐れずに、モジュールを自由に定義できます. 
次に、定義されたモジュールを使用する必要があります.
定義されたモジュールを使用する場合は、モジュール自体ではなく、そのコピーを使用します.利点は、モジュールを毎回呼び出す必要がなく、各モジュールをユーザーに個別にコピーすることです.すなわち、使用者に生産される.
 
 
この部分は後ろの文章に置いて展開します.