ホームページ  >  記事  >  ウェブフロントエンド  >  jQuery_jquery のプログラミング パラダイムの詳細な説明

jQuery_jquery のプログラミング パラダイムの詳細な説明

WBOY
WBOYオリジナル
2016-05-16 16:27:011480ブラウズ

この記事では、jQuery のプログラミング パラダイムを詳細に分析します。皆さんの参考に共有してください。詳細は以下の通りです。

ブラウザ フロントエンド プログラミングの様相は、2005 年以来大きく変化しました。これは単に、豊富な機能を備えた多数の基本ライブラリが登場し、ビジネス コードをより便利に記述できるようになったことを意味するものではありません。フロントエンドテクノロジーに対する見方が大きく変わり、フロントエンド特有の方法でプログラマーの生産性を解放する方法が明確に意識されました。ここでは、jQuery ソース コードの実装原則に基づいて、JavaScript で出現するプログラミング パラダイムと一般的なテクニックを簡単に紹介します。

1. AJAX: 状態の永続化、非同期更新

まず、少し歴史を説明します。

A. 1995 年に、Netscape の Brendan Aich は、動的で弱い型付けのプロトタイプベースのスクリプト言語である JavaScript 言語を開発しました。
B. 1999 年に、XMLHTTP ActiveX コントロールを含む Microsoft IE5 がリリースされました。
C. Microsoft IE6 は 2001 年にリリースされ、DOM レベル 1 および CSS 2 標準を部分的にサポートしました。
D. Douglas Crockford は 2002 年に JSON 形式を発明しました。

現時点では、Web 2.0 が依存する技術要素は基本的に形になったと言えますが、すぐに業界全体に重大な影響を与えたわけではありません。いくつかの「非同期部分ページ更新」テクニックがプログラマの間で秘密裏に広まり、bindow のような巨大で肥大化したクラス ライブラリさえも生み出しましたが、一般に、フロントエンドは不毛で汚い沼地とみなされ、バックエンド テクノロジだけが王様です。何が欠けている?

現在の視点で 2005 年以前の JS コードを振り返ると、当時の優秀な人材が書いたコードも含めて、プログラム制御の弱点がはっきりと感じられます。 2005 年以前の js テクノロジー自体に問題があったわけではなく、概念レベルで分散していたり​​、統一されたコンセプトがなかったり、独自のスタイルや魂が欠けていたりするだけです。当時、ほとんどの人やテクノロジーは、従来のオブジェクト指向言語をシミュレートし、従来のオブジェクト指向テクノロジーを使用して従来の GUI モデルの模倣を実装しようとしていました。

2005 年は変化の年であり、コンセプト創造の年でした。 Google による一連の斬新なインタラクティブ アプリケーションのリリースに伴い、Jesse James Garrett による記事「Ajax: A New Approach to Web Applications」が広く広まりました。フロントエンド固有の概念である Ajax は、多くの分散した実践を同じスローガンの下ですぐに統合し、Web プログラミングのパラダイム シフトを引き起こしました。ことわざにあるように、名前が正しくなければ、言葉も正しくありません。今では、無名の大衆が組織を見つけることができます。 Ajax が登場する前は、B/S アーキテクチャの本質的な特徴はブラウザとサーバーの状態空間が分離されていることであると人々は長い間認識していました。しかし、一般的な解決策は、この区別を隠し、フォアグラウンド状態をバックグラウンドに同期させることでした。 ASP.NET などの統合論理処理。フォアグラウンド状態の永続性をサポートする成熟したデザイン パターンが不足しているため、ロードされた js オブジェクトは、このようにして、複雑な作業を完了することを期待できますか?

Ajax は、インターフェイスが部分的に更新され、状態がフォアグラウンドに存在することを明確に示しています。これは、js オブジェクトがフォアグラウンドに長時間存在する必要があるというニーズを促進します。これは、これらのオブジェクトと機能を効果的に管理する必要があることも意味します。これは、より複雑なコード編成テクノロジを意味し、モジュール性と共通のコード ベースが必要になることを意味します。

jQuery の既存のコードには実際に Ajax に関連する部分はほとんどありません (XMLHTTP コントロールを使用してバックグラウンドの戻りデータに非同期にアクセスします)。しかし、Ajax がなければ、jQuery はパブリック コード ベースとして存在する理由がありません。

2. モジュール化: 名前空間の管理

大量のコードが生成される場合、必要となる最も基本的な概念はモジュール化です。これは、作業を分解して再利用することです。仕事を分解する鍵は、各人の独立した仕事の結果を統合できることです。これは、各モジュールが一貫した基礎的な概念に基づいており、相互作用できる必要があることを意味します。つまり、共通のコード ベースに基づき、基礎となるブラウザーの不整合を保護し、統合された抽象化レイヤーを実装する必要があります。統合されたイベント管理メカニズム。統一されたコード ベースよりも重要なのは、モジュール間で名前の競合があってはなりません。そうしないと、2 つのモジュールは相互作用がなくても連携して動作しません。

jQuery が現在宣伝している主なセールス ポイントの 1 つは、名前空間を適切に制御できることです。これは、より多くの完全な機能ポイントを提供することよりもさらに重要です。モジュール性が優れているため、あらゆるソースからコードを再利用でき、全員の作業を蓄積して重ね合わせることができます。また、関数の実装は一時的な作業負荷にすぎません。 jQuery は、グローバル名前空間への影響を軽減するためにモジュール パターンのバリアントを使用し、jQuery オブジェクト (つまり $function) を window オブジェクトに追加するだけです。

いわゆるモジュール パターン コードは次のとおりです。重要なのは、匿名関数を使用して一時変数の範囲を制限することです。

コードをコピー コードは次のとおりです:
var feature =(function() {

//プライベート変数と関数
var privateThing = '秘密',
PublicThing = '秘密ではない',

changePrivateThing = function() {
privateThing = '超秘密';
}、

sayPrivateThing = function() {
console.log(privateThing);
changePrivateThing();
};

// パブリック API に戻ります
戻り値 {
パブリックシング: パブリックシング、
SayPrivateThing :sayPrivateThing
}
})();

JS 自体にはパッケージ構造がありませんが、長年の試みを経て、業界はパッケージの読み込みに関する理解を徐々に統一し、一定のコンセンサスを得た RequireJs ライブラリのようなソリューションを形成しました。 jQuery は RequireJS ライブラリと適切に統合され、より完全なモジュールの依存関係管理を実現できます。 http://requirejs.org/docs/jquery.html

コードをコピーします コードは次のとおりです:
require(["jquery", "jquery.my"], function () {
// jquery.js と jquery.my.js の両方が正常にロードされたときに実行
$(関数(){
$('#my').myFunc();
});
});


モジュール my/shirt は、my/cart モジュールと my/inventory モジュールに依存する次の関数呼び出しを通じて定義されます。
コードをコピーします コードは次のとおりです:
require.def("my/shirt",
["私の/カート"、"私の/在庫"]、
関数(カート、在庫) {
// ここでモジュール パターンを使用して、my/shirt モジュールによって公開される API を返します
return {
カラー: "青"、
サイズ:「ラージ」
addToCart: function() {
// デクリメントは my/inventory
によって公開される API です Inventory.decrement(this);
cart.add(this);
}
}
}
);

3. Magic$: オブジェクトのプロモーション

$ 関数を初めて見たとき、何を思いましたか?従来のプログラミング理論では、関数の命名は正確であるべきであり、作成者の意図を明確に表現する必要があると常に言われており、曖昧さの可能性を減らすため、短い名前よりも長い名前の方が優れているとさえ主張しています。しかし、$ とは何でしょうか?コードが文字化けしていませんか?それが伝えるメッセージはあまりにも曖昧で曖昧です。 $ は、prototype.js ライブラリによって発明され、プリミティブな DOM ノードを複雑な動作を持つオブジェクトに拡張できるため、まさに魔法の関数です。 prototype.js の元の実装では、$function は
として定義されていました。

コードをコピー コードは次のとおりです。
var $ = function (id) {
"文字列" == typeof id ? document.getElementById(id) : id;
を返す };

これは基本的に次の式に対応します
e = $(id)

これは、関数名の略語が巧妙であるだけでなく、さらに重要なことに、概念レベルでテキスト ID と DOM 要素の間に 1 対 1 の対応関係が確立されることです。 $ が存在する前は、ID と対応する要素の間の距離が非常に遠いため、要素は
などの変数にキャッシュする必要があります。

コードをコピーします コードは次のとおりです:
var ea = docuement.getElementById('a');
var eb = docuement.getElementById('b');
ea.style....

しかし、$ を使用すると、どこにでも次のような記述が見られます
コードをコピー コードは次のとおりです:
$('header_' id).style...
$('body_' id)....

id と要素の間の距離がなくなり、非常に密接に絡み合っているように見えます。

prototype.js は後に $、
の意味を拡張しました。

コードをコピー コードは次のとおりです。
function $() {
var 要素 = new Array();

for (var i = 0; i < argument.length; i ) {
var 要素 = 引数[i];
If (要素の種類 == '文字列')
要素 = document.getElementById(element);

if (arguments.length == 1)
戻り要素;

elements.push(element);
}

要素を返します;
}

これは次の式に対応します:
[e,e] = $(id,id)

残念ながら、prototype.js はこのステップで道を誤ったため、このアプローチには実用的な価値はほとんどありません。
実際に $ を促進するのは jQuery であり、その $ は式
に対応します。 [o] = $(セレクター)
以下に 3 つの機能強化を示します:
A. セレクターは単一ノード ロケーターではなく、複雑なコレクション セレクター
になりました。 B. 返される要素は元の DOM ノードではなく、jQuery によってさらに強化された豊富な動作を備えたオブジェクトであり、複雑な関数呼び出しチェーンを開始できます。
C. $ によって返されるパッケージング オブジェクトは配列形式に整形され、コレクション操作が呼び出しチェーンに自然に統合されます。

もちろん、上記は魔法の $ を単純化しすぎた説明であり、実際の機能は、特によく使用される直接構築関数です。

コードをコピー コードは次のとおりです。
$("
")....

jQuery は、受信した HTML テキストに基づいて一連の DOM ノードを直接構築し、それらを jQuery オブジェクトとしてパッケージ化します。これは、ある程度セレクターの拡張と見なすことができます。つまり、HTML コンテンツの記述自体が独自の指定です。

$(function{}) この関数は実際には少し言葉にならないのですが、これは document.ready のときにこのコールバック関数が呼び出されるということです。本当に、$ は魔法の関数です。ご不明な点がございましたら、お問い合わせください。

要約すると、$ は、通常の DOM とテキスト記述の世界から、リッチ オブジェクト動作を備えた jQuery の世界への移行チャネルです。この扉を越えると、私たちはユートピアに到着しました。

4. 非晶質パラメータ: 制約ではなく表現に焦点を当てる

弱い型付け言語には「弱い」という言葉が付いているため、プログラムに型制約がないことは、本当に伝統的な強い型付け言語の大きな欠点なのでしょうか。関数のパラメータの型と数はすべてコンパイラによってチェックされる制約ですが、一般的なアプリケーションでは制約を強化するために、C We などで常に大量の防御コードが追加されます。 ASSERT は一般的に使用され、Java ではパラメータ値の範囲を決定する必要があることがよくあります

コードをコピー コードは次のとおりです:
if (index < 0 || Index >= size)
throw new IndexOutOfBoundsException(
"インデックス: " インデックス "、サイズ: " サイズ);

明らかに、これらのコードはプログラム内に多数の非機能的な実行パスを引き起こすことになります。つまり、多くの判断が行われ、コードが特定の点まで実行されると、システムは例外をスローし、次のことを叫びます。このパスはブロックされています。考え方を変えると、特定の判断を行った後、その判断の結果を使用して何かを行うことができるでしょうか。この傾向に従うと、JavaScript は弱い型指定を行うことができません。パラメータの形状をさらに弱めると、「弱さ」が極限まで押し上げられ、弱さが何もないとき、弱さが象徴的な機能になるでしょうか?

jQuery のイベント バインディング関数 binding を見てください。
A. 一度に 1 つのイベントをバインドします

コードをコピー コードは次のとおりです:
$("#my") .bind(" マウスオーバー", function(){});

B. 複数のイベントを一度にバインドする
コードをコピー コードは次のとおりです:
$("#my") .bind( "マウスオーバー マウスアウト",function(){})

C. フォームを変更して複数のイベントをバインドする
コードをコピー コードは次のとおりです。
$("#my").bind({mouseover:function( ){} 、mouseout:function(){});

D. いくつかのパラメーターをイベント リスナーに渡したい
コードをコピー コードは次のとおりです:
$('#my').bind('click', { foo: " xxxx"}, function(event) {event.data.foo..})

E. イベントリスナーをグループ化したい
コードをコピー コードは次のとおりです:
$("#my").bind("click.myGroup" 、関数( ){});

F. なぜこの関数はおかしくなっていないのでしょうか???

型が不確かでも、固定位置のパラメータの意味は確かでなければなりませんよね? 一歩下がって、パラメータの位置が重要でなくても、関数自体の意味は確かである必要がありますよね?これは?

値 value = o.val()、設定値 o.val(3)

渡されるパラメータの種類や数に応じて、関数がどのようにして動作が異なるのでしょうか? しかし、これは防ぐことができないため、意図的に許可されています。変化の形はたくさんありますが、抑制の欠如は表現を妨げるものではありません(私は人々を怖がらせるためにここにいるわけではありません)。

5. チェーン操作: 線形化の段階的な改善

初期の jQuery の主なセールスポイントは、いわゆるチェーン操作でした。


コードをコピー コードは次のとおりです:
$('#content') // コンテンツ要素を検索します
.find('h3') // すべての子孫 h3 ノードを選択します
.eq(2) // コレクションをフィルタリングし、3 番目の要素を保持します
.html('3番目のh3のテキストを変更')
.end() // 前の h3 コレクションに戻ります
.eq(0)
.html('最初の h3 のテキストを変更');

一般的な命令型言語では、常にネストされたループでデータをフィルタリングする必要があり、実際にデータを操作するコードとデータを見つけるコードが絡み合っていますが、jQuery では、最初にコレクションを構築してから適用する方法が使用されます。実際、このメソッドは、$('div.my input:checked') のような手続き的思考に頼ることなく、2 つのロジックの分離と入れ子構造の線形化を実現します。プロセス動作の追跡ではなく、直接的な説明として見ることができます。

ループとは、思考が巻き戻しを繰り返している状態を意味し、線形化後は一方向に直進するため、思考の負担が大幅に軽減され、呼び出しの中断を減らすためにコードの構成可能性が向上します。 chain では、jQuery が素晴らしいアイデアを発明しました。jQuery は、オブジェクト自体を配列 (コレクション) のようにラップし、コレクションを新しいコレクションにマッピングでき、コレクションを独自のサブコレクションに制限できます。呼び出しの開始者はコレクションであり、返されるコレクションはコレクションです。 result もコレクションです。 いくつかの構造上の変更が発生していますが、依然としてセットです。これは関数型言語から吸収された設計上の考え方です。 Java では、コレクション操作は非常に一般的な操作です。jQuery では、多くのいわゆるカプセル化関数が実際にいくつかのコレクション トラバーサル操作をカプセル化していることが簡単にわかります。

連鎖呼び出しとは、常に「現在の」オブジェクトがあり、すべての操作がこの現在のオブジェクトに対して実行されることを意味します。これは次の式に対応します
x = dx
呼び出しチェーンの各ステップは、現在のオブジェクトの増分記述であり、最終目標に向けた段階的な改良プロセスです。このアイデアは Witrix プラットフォームでも広く使用されています。特にプラットフォームの仕組みと業務コードの統合を実現するために、プラットフォームはオブジェクト(コンテナ)の内容をデフォルトで提供し、これをベースに業務コードを段階的に改良・修正(デフォルト設定の解除も含む)することが可能です。

とはいえ、jQuery のチェーン呼び出しは表面的には非常に単純ですが、コンパイラーは「コレクション内の各要素に自動的に適用する」ことを認識しないため、内部で実装する場合は追加のループ層を記述する必要があります。

コードをコピー コードは次のとおりです。
$.fn['someFunc'] = function(){
return this.each(function(){
jQuery.someFunc(this,...);
}
}


6. データ: 統合されたデータ管理

js ライブラリとして解決しなければならない大きな問題は、js オブジェクトと DOM ノードの間の状態の関連付けと共同管理です。一部の js ライブラリは、js オブジェクトに焦点を当て、アクセスするときに常に js オブジェクトをエントリ ポイントとして使用し、js 関数を通じて DOM オブジェクトを間接的に操作します。この種のカプセル化では、DOM ノードは実際にはインターフェイスとして表示される低レベルの「アセンブリ」にすぎません。 jQuery の選択は、HTML 自体の構造に基づいた Witrix プラットフォームと似ており、js を通じて DOM ノードの機能を強化し、複雑な動作を備えた拡張オブジェクトに昇格します。ここでの考え方は、非侵入型設計 (非侵入型) とグレースフル デグラデーション メカニズム (グレースフル デグラデーション) です。セマンティック構造は基本的な HTML レベルで完成します。js の役割は、インタラクティブな動作を強化し、プレゼンテーション フォームを制御することです。

毎回 $('#my') を通じて対応するパッケージング オブジェクトにアクセスする場合、長期間維持する必要がある状態変数はどこに格納されるのでしょうか? jQuery は、統一されたグローバル データ管理メカニズムを提供します。

データの取得:

コードのコピー コードは次のとおりです:
$('#my').data ('myAttr ')

データを設定します:
コードをコピー コードは次のとおりです:
$('#my').data('myAttr ',3 );

このメカニズムには、HTML5 データ属性の処理が自然に統合されています
コードをコピー コードは次のとおりです:

HTML に設定されたデータは、$('#my').data('myAttr') を通じて読み取ることができます。

初めてデータにアクセスするとき、jQuery は一意の uuid を DOM ノードに割り当て、それを DOM ノードの特定の Expando 属性に設定して、この uuid がこのページで繰り返されないようにします。

コードをコピー コードは次のとおりです:
elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

上記のコードは、DOM ノードと純粋な JS オブジェクトの両方を処理できます。 jsオブジェクトの場合はjsオブジェクト自体に直接データが配置され、DOMノードの場合はキャッシュを通じて一元管理されます。

すべてのデータはデータ メカニズム、特にすべてのイベント リスニング関数 (data.events) を通じて均一に管理されるため、jQuery はリソース管理を安全に実装できます。ノードのクローンを作成する場合、その関連するイベント リスニング機能を自動的にクローン作成できます。 DOM ノードのコンテンツが置き換えられた場合、または DOM ノードが破壊された場合、jQuery はイベント リスニング機能を自動的にキャンセルし、関連する js データを安全に解放することもできます。

7. イベント: 統一イベントモデル

「オブジェクト ツリーに沿って伝播するイベント」の図は、オブジェクト指向インターフェイス プログラミング モデルの本質です。オブジェクトの構成は、インターフェイス構造の安定した記述を構成します。イベントはオブジェクト ツリーの特定のノードで継続的に発生し、バブリング メカニズムを通じて上方に伝播します。オブジェクト ツリーは、当然のことながら、各子ノードとの関連付けを明示的に確立しなくても、親ノード上のすべての子ノードのイベントをリッスンすることができます。

さまざまなブラウザのイベント モデルの統一された抽象化を確立することに加えて、jQuery は主に次の機能強化を行いました。 A. カスタム イベント (カスタム) メカニズムを追加しました。イベント伝播メカニズムは原則としてイベントの内容自体とは関係がないため、カスタム イベントはブラウザーの組み込みイベントと同じ処理パスを通過し、同じ監視方法を使用できます。カスタム イベントを使用すると、コードの結合度が高まり、コードの結合が軽減されます。たとえば、カスタム イベントがない場合、関連するコードが関連オブジェクトを直接操作する必要があることがよくあります。

コードをコピー コードは次のとおりです。$('.switch, .clapper').click(function( ) {
var $light = $(this).parent().find('.lightbulb');
If ($light.hasClass('on')) {
$light.removeClass('on').addClass('off');
} else {
$light.removeClass('off').addClass('on');
}
});

カスタム イベントを使用する場合、表現されるセマンティクスはより抑制され、明確になります。


コードをコピー コードは次のとおりです。$('.switch, .clapper').click(function( ) {
$(this).parent().find('.lightbulb').trigger('changeState');
});

B. 動的に作成されたノードのイベント監視を追加しました。バインド関数は既存の DOM ノードにのみ登録できます。たとえば、


コードをコピー コードは次のとおりです:$('li.trigger').bind('click', function() {}}
bind の呼び出し後に別の li ノードが作成された場合、このノードのクリック イベントは監視されません。

jQuery のデリゲート機構は、親ノードに listen 関数を登録することができ、子ノードでトリガーされたイベントは、セレクターに従って、対応する handlerFn に自動的にディスパッチされます。このように、今登録すると、listen することができます。今後作成されるノード


コードをコピー コードは次のとおりです:$('#myList').delegate('li.trigger' 、'クリック'、handlerFn);
最近、jQuery 1.7 ではバインド、ライブ、デリゲートのメカニズムが統合され、オン/オフのみで世界が統一されました。


コードをコピー コードは次のとおりです:$('li.trigger').on('click', handlerFn); // binding
と同等 $('#myList').on('click', 'li.trigger', handlerFn); // デリゲート
と同等

8. アニメーション キュー: グローバル クロック調整

jQuery の実装はさておき、インターフェイス上でアニメーション効果を実現したい場合、まず何をする必要があるかを考えてみましょう。たとえば、div の幅を 1 秒以内に 100px から 200px に増やしたいとします。一定期間にわたって div の幅を時々調整する必要があることは容易に想像できますが、[同時に] 通常の関数呼び出しとは異なり、アニメーション コマンドを発行した後、他のコードも実行する必要があります。必要なものがすぐに得られるとは期待できません。また、結果が届くのをただ待つこともできません。アニメーションの複雑さは、1 回限りの式の後に一定期間内に実行する必要があることにあります。同時に展開する必要がある複数の論理実行パスを調整するには?

偉大なアイザック・ニュートン卿は、「自然哲学の数学的原理」の中で、「すべての出来事はタイムライン上で整列することができ、それは、ステップを実行するための固有の調整です。」 A1 から A5 とステップ B1 から B5 を同時に実行する必要があるのは、時刻 t1 で [A1, B1] を実行し、時刻 t2 で [A2, B2] を実行するだけです。 t1 | t2 | t5 ...

A1 | A2 | A5 ...
B1 | B2 | B5 ...

特定の実装フォームは次のとおりです

A. アニメーションごとに、Animation オブジェクトに分割し、内部で複数のステップに分割します。

アニメーション = 新しいアニメーション(div,"width",100,200,1000,
ステップのセグメント化を担当する補間関数と、アニメーションが完了したときのコールバック関数); B. グローバルマネージャーにアニメーションオブジェクトを登録
timerFuncs.add(アニメーション);
C. グローバル クロックのトリガーの瞬間ごとに、登録された各実行シーケンスをさらに 1 ステップ進め、終了した場合はグローバル マネージャーから削除します。



コードをコピー コードは次のとおりです:timerFuncs の各アニメーション if(!animation.doOneStep())
timerFuncs.remove(アニメーション)


原理的な問題を解決したら、最もコンパクトな形式で意図を表現するためにインターフェイス関数を設計する方法について考えてみましょう:

A. 同様のアニメーションを実行するには複数の要素があります
B. 各要素には同時に変更する必要がある複数の属性があります

C. アニメーションを 1 つ実行した後、別のアニメーションを開始します

これらの質問に対する jQuery の答えは、js の文法表現の最後の残りの値を絞り出すものであると言えます。



コードをコピー

コードは次のとおりです:$('input') .animate({left:' =200px',top:'300'},2000) .animate({left:'-=200px',top:20},1000)
.queue(function(){
//ここで、デキューは最初にキュー内の最後の関数を実行するため、alert("y")
$(this).dequeue();
アラート('x');
})
.queue(function(){
アラート("y");
// 積極的にデキューしない場合、キューの実行は中断され、自動的には続行されません。
$(this).dequeue();
});

A. jQuery の組み込みセレクター メカニズムを使用して、コレクションの処理を自然に表現します。
B. Map を使用して複数の属性の変更を表現します
C. マイクロフォーマットを使用してドメイン固有のデルタ概念を表現します。「=200px」は、既存の値に 200px を追加することを意味します
D. 関数呼び出しの順序を使用して、アニメーションの実行順序を自動的に定義します。実行キューに追加されたアニメーションは、前のアニメーションが完全に実行されるまで自然に待機してから開始されます。

jQueryアニメーションキューの実装詳細は大まかに以下のとおりです。

A. animate 関数は実際には queue(function(){実行の最後に dequeue を呼び出す必要があります。そうしないと次のメソッドは実行されません})
キュー関数が実行されるとき、それが fx キューであり、現在アニメーションが実行されていない場合 (animate が 2 回続けて呼び出された場合、2 番目の実行関数はキュー内で待機します)、デキュー操作が自動的にトリガーされて、実行するキュー。
fx キューの場合、デキュー時に「inprogress」文字列がキューの先頭に自動的に追加され、アニメーションが実行されようとしていることを示します
。 B. プロパティごとに、jQuery.fx オブジェクトを作成します。次に、fx.custom 関数 (start と同等) を呼び出してアニメーションを開始します。
C. カスタム関数で、fx.step 関数をグローバル timerFuncs に登録し、グローバル タイマーを開始してみます。
timerId = setInterval( fx.tick, fx.interval );
D. 静的ティック関数は、各 fx のステップ関数を順番に呼び出します。ステップ関数では、アトリビュートの現在値がイージングによって計算され、その後 fx の update が呼び出されてアトリビュートが更新されます。
E. fx のステップ関数は、すべての属性変更が完了すると、デキューが呼び出され、次のメソッドが実行されると判断します。

非常に興味深いのは、jQuery 実装コードには明らかに多くのリレー トリガー コードがあることです。次のアニメーションを実行する必要がある場合は、それを取り出して実行し、タイマーを開始する必要がある場合はタイマーを開始し、これは、js プログラムがシングルスレッドであるためです。実行スレッドが中断されないようにするには、複数の実行がある場合、関数が互いに助け合う必要があることが考えられます。プログラム内のエンジン、さらには無限実行エンジンを使用すると、プログラムの外観が本質的に変わります。この場合、再帰はループと比較してより自然な記述になります。

9. 約束のパターン: 因果関係の特定

現実には、常に多くのタイムラインが独立して進化し、人や物が時間と空間で交差しますが、ソフトウェアではソースコードに関数が並んでおり、必然的にいくつかの疑問が生じます。どうして先頭にいる奴が先に処刑されなければならないの? 1、2、3と叫びながら全宇宙が前進するだろう。は相対性理論です。情報の交換がなく相互依存性がない場合、ある座標系で連続して発生するイベントは、別の座標系で見ると逆の順序に見えることがあります。その後、Promise パターンを発明しました。

Promise パターンと future パターンは基本的に同じものです。まず、Java でおなじみの future パターンを見てみましょう。


コードをコピー コードは次のとおりです:
futureResult = doSomething();
...
realResult = futureResult.get();
関数呼び出しの発行は、何かが起こったことを意味するだけであり、呼び出し元がその問題の最終結果を知る必要があることを必ずしも意味するわけではありません。関数が即座に返すのは、実行される約束 (Future 型) にすぎません。未来、実際には何らかのハンドルが渡され、途中で手を変えるコードは、コードの一部が依存する必要があるまで、実際の結果が何であるか、それが返されたかどうかには無関係です。実際の結果が返された場合、future.get() は実際の結果をすぐに返します。それ以外の場合は、結果が返されるまで現在の実行パスをブロックします。その後に future.get() を呼び出すと、因果関係が確立されているため、常にすぐに戻ります。[結果が返される] このイベントはこれより前に発生している必要があり、再度変更されることはありません。

Future モードは通常、外部オブジェクトが Future の戻り値を積極的にチェックすることを意味し、Promise モードは外部オブジェクトが Promise にコールバック関数を登録することを意味します。


コードをコピー コードは次のとおりです:
関数 getData(){
戻り値 $.get('/foo/').done(function(){
console.log('AJAX リクエストが成功した後に起動');
}).fail(function(){
console.log('AJAX リクエストが失敗した後に起動');
});
}

関数 showDiv(){
var dfd = $.Deferred();
$('#foo').fadeIn( 1000, dfd.resolve );
dfd.promise();
を返します }

$.when( getData(), showDiv() )
.then(function(ajaxResult,ignoreResultFromShowDiv){
console.log('showDiv() と AJAX リクエストの両方が成功した後に起動します!');
// 'ajaxResult' はサーバーの応答です
});

jQuery は Deferred 構造を導入し、promise モードに従って ajax、queue、document.ready などを再構築し、非同期実行メカニズムを統合します。 then(onDone, onFail) は、promise にコールバック関数を追加します。呼び出しが正常に完了すると (解決)、コールバック関数 onDone が実行され、呼び出しが失敗した場合 (拒否)、promise の賢い点は、非同期実行後に onFail が実行されることです。開始または終了しましたが、コールバック関数を登録することはまだ可能です

someObj.done(callback).sendRequest() と someObj.sendRequest().done(callback)

非同期呼び出しを発行する前にコールバック関数を登録することも、非同期呼び出しを発行した後に登録することも完全に同等であることは、プログラムの表現が完全に正確であることはなく、この固有の次元が効果的に可能である場合には常に固有の変更が存在することを示しています。可変性により、同時実行プログラムのパフォーマンスが大幅に向上します。

Promise モードの具体的な実装は非常に簡単です。jQuery._Deferred は次の関数を含む関数キューを定義します。

A. コールバック関数を保存します。
B. 解決または拒否時に、保存されているすべての関数を実行します。
C. 実行後、追加の関数はすぐに実行されます。

E 言語など、分散コンピューティングまたは並列コンピューティングに特化した一部の言語には、言語レベルで Promise モードが組み込まれています。

コードをコピー コードは次のとおりです。
def carPromise := carMaker <-Produce("Mercedes");
Def 温度プロミス := carPromise <- getEngineTemperature()
...
いつ (温度約束) -> 完了 (温度) {
println(`車のエンジンの温度は $temperature`)
} キャッチ e {
println(`エンジン温度を取得できませんでした、エラー: $e`)
}
E 言語では、<- は最終的に実行されることを意味しますが、通常の car.moveTo(2,3) はすぐに実行されて結果が取得されることを意味します。コンパイラはすべての Promise 依存関係を識別し、自動的にスケジューリングを実装します。

10. 拡張: 継承は必要ありません
JS はプロトタイプベースの言語であり、継承メカニズムが組み込まれていないため、従来のオブジェクト指向教育を深く学んできた多くの学生は常に悩まされてきました。しかし、それは私たちに何をもたらすのでしょうか?最も簡単な答えは、コードの再利用です。そこで、まず、コードの再利用の手段としての継承の可能性を分析しましょう。

かつては「多重遺伝」と呼ばれる概念がありましたが、これは遺伝の概念の超サイヤ人バージョンであり、残念なことに、後に先天性欠陥があると診断され、遺伝の概念の次のような解釈が生まれました。継承は " is a" 関係であり、派生オブジェクト "is a" には多くの基底クラスがあり、必然的に統合失調症につながるため、多重継承は良くありません。


コードをコピー コードは次のとおりです。class A{ public: void f(){ f in A } } class B{ public: void f(){ f in B } }
クラス D: パブリック A、B{}

クラス D が 2 つの基本クラス A と B から継承し、クラス A と B の両方が同じ関数 f を実装している場合、クラス D の f は A の f または B の f です。それとも f はどうですか?このジレンマの出現は、実際には、D の基底クラス A と B が、概念レベルで交換法則と結合法則を満たすという事実から生じています。どのような概念間にも 2 つの従属関係が現れることを認識するのは難しいかもしれませんが、概念的レベルの要件を緩和し、コードの再利用の問題を運用レベルから考慮すると、B は A に基づいて動作すると単純に考えることができます。つまり、A と B の間の交換法則を放棄し、結合法則だけを保持すると、A、B を拡張する場合と B、A を拡張する場合とで、2 つの異なる結果が得られます。 scala 言語のいわゆるトレイト メカニズムは実際にこの戦略を採用しています。

オブジェクト指向技術の発明からずっと後、いわゆるアスペクト指向プログラミング (AOP) が登場しました。これは、AOP がコード構造空間内での位置付けと変更の技術であるという点で OOP とは異なります。 AOP は、多重継承と同様のコード再利用メソッドを提供します。これは、オブジェクトを任意に開いて変更できる Map と見なされます。オブジェクト本体に直接挿入され、その動作が直接変更されます。 prototype.js ライブラリには、extend 関数
が導入されています。

コードをコピー コードは次のとおりです。
Object.extend = function(destination, source) {
for (ソース内の var プロパティ) {
宛先[プロパティ] = ソース[プロパティ];
}
戻り先;
}
はマップ間のカバー操作ですが、非常に効果的であり、jQuery ライブラリで拡張されています。この操作は、jQuery でのコード再利用の主要な技術的手段である mixin に似ています。これは大したことではありません。の継承がない場合。

11. 名前のマッピング: すべてはデータです

コードが優れていれば、ループ判定は少なくなるはずです。ループと判定ステートメントはプログラムの基本コンポーネントですが、これらのステートメントが織り交ぜられると主線が曖昧になってしまうため、優れたコード ライブラリには存在しないことがよくあります。システムのロジックの複雑なコード トレースに没頭してみましょう。jQuery 自体は、each や extend などの関数によるループ ステートメントの必要性を大幅に減らし、たとえば、マッピング テーブルを通じて処理されます。 jQueryのval()関数はタグごとに異なる処理を行う必要があるため、tagNameをキーとした関数マッピングテーブルを定義します


コードをコピー コードは次のとおりです:
valHooks: { option: {get:function(){}}}
こうすることで、プログラム内のあらゆる場所に
を記述する必要がなくなります。
コードをコピーします コードは次のとおりです:
if(elm.tagName == 'OPTION'){
戻る ...;
}else if(elm.tagName == 'TEXTAREA'){
戻る ...;
}
統一的に処理できる

コードをコピー コードは次のとおりです:
(valHooks[elm.tagName.toLowerCase()] || defaultHandler) .get(ニレ);

マッピング テーブルは関数を通常のデータとして管理し、特にオブジェクト自体が関数や変数のコンテナーであり、名前マッピングを動的に使用する手法として動的言語で広く使用されています。たとえば、2 つの非常によく似た関数 myWidth と myHeight を実装するために、
は必要ありません。
コードをコピー コードは次のとおりです。
jQuery.fn.myWidth = function(){
戻り parseInt(this.style.width,10) 10;
}

jQuery.fn.myHeight = function(){
戻り parseInt(this.style.height,10) 10;
}
代わりに、
を動的に生成することを選択できます。
コードをコピー コードは次のとおりです:
jQuery.each(['幅','高さ'],関数(名前){
jQuery.fn['my' name] = function(){
return parseInt(this.style[name.toLowerCase()],10) 10;
}
});


12. プラグインの仕組み: 実はとてもシンプルです

jQuery のいわゆるプラグインは、実際には $.fn に追加された関数です。では、この fn とは何でしょうか?

コードをコピー コードは次のとおりです。
(function(window,unknown){
// 中には別のパッケージがあります
var jQuery = (function() {
var jQuery = function(セレクター, コンテキスト) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
....
// fn は実際にはプロトタイプの略語です
jQuery.fn = jQuery.prototype = {
コンストラクター: jQuery,
init: function(selector, context, rootjQuery) {... }
}

// jQuery() の呼び出しは new init() と同等であり、init のプロトタイプは jQuery
のプロトタイプです jQuery.fn.init.prototype = jQuery.fn;

// // ここで返される jQuery オブジェクトには、最も基本的な関数のみが含まれています。 以下は一連の extend
です。 jQuery を返します;
})();
...
// jQuery をグローバル オブジェクトとして公開します
window.jQuery = window.$ = jQuery;
})(ウィンドウ);

明らかに、$.fn は実際には jQuery.prototype
の略称です。
ステートレス プラグインは単なる関数であり、非常に単純です。

コードをコピー コードは次のとおりです:
// プラグインを定義します
(関数($){
$.fn.hoverClass = function(c) {
return this.hover(
function() { $(this).toggleClass(c) }
);
};
})(jQuery);

//プラグインを使用します
$('li').hoverClass('hover');

より複雑なプラグイン開発のために、jQuery UI はウィジェット ファクトリ メカニズム
を提供します。
コードをコピーします コードは次のとおりです:
$.widget("ui.dialog", {
オプション: {
autoOpen: true,...
}、
_create: function(){ ... },
_init: function() {
if ( this.options.autoOpen ) {
This.open();
}
}、
_setOption: function(key, value){ ... }
破棄: function(){ ... }
});

$('#dlg').dialog(options) を呼び出す場合、実行される実際のコードは基本的に次のとおりです:

コードをコピー コードは次のとおりです:
this.each(function() {
var インスタンス = $.data( this, "ダイアログ" );
if ( インスタンス ) {
Instance.option( options || {} )._init();
} else {
$.data( this, "ダイアログ", new $.ui.dialog( options, this ) );
}
}

$('#dlg').dialog() 関数が初めて呼び出されたときに、ウィンドウ オブジェクト インスタンスが作成され、_create() 関数と _init() 関数がデータに保存されることがわかります。初めて呼び出されない場合、_init() メソッドは既存のオブジェクト インスタンスに対して呼び出されます。 $('#dlg').dialog() を複数回呼び出しても、複数のインスタンスは作成されません。

13. ブラウザスニファーと機能検出

ブラウザ スニッファは、jQuery の初期など、かつて非常に人気のあるテクノロジでした

コードをコピー コードは次のとおりです。
jQuery.browser = {
バージョン:(userAgent.match(/. (?:rv|it|ra|ie)[/: ]([d.] )/) || [0,'0'])[1],
safari:/webkit/.test(userAgent),
opera:/opera/.test(userAgent),
msie:/msie/.test(userAgent) && !/opera/.test(userAgent),
mozilla:/mozilla/.test(userAgent) && !/(compatibility|webkit)/.test(userAgent)
};

特定のコードでは、ブラウザごとに異なる処理を実行できます

コードをコピー コードは次のとおりです。
if($.browser.msie) {
// 何かをします
} else if($.browser.opera) {
// ...
}

しかし、ブラウザ市場での競争が激化するにつれ、競合他社が互いに模倣したり偽装したりする結果、Chrome の誕生と Safari の台頭と相まって、IE も標準への移行を加速し始めています。プラスの効果として、より詳細でより具体的な検出方法として、ブラウザの互換性を扱う方法が徐々に主流になってきています。

コードをコピー コードは次のとおりです。
jQuery.support = {
// .innerHTML が使用される場合、IE は先頭の空白を削除します
leadingWhitespace: ( div.firstChild.nodeType === 3 ),
...
}
かつて知っていたことではなく、実際に見たものにのみ基づいているため、将来への対応が容易になります。

14. プロトタイプと jQuery

prototype.js は、高い志を持ったライブラリであり、その目標は、新しいユーザー エクスペリエンスを提供し、Ruby を参照して JavaScript を言語レベルから変換し、最終的には js の顔を大きく変えることです。 $、extends、 each、bind... これらのおなじみの概念はすべて、prototype.js によって js フィールドに導入されます。これを最初に利用するのは誰の勢いですか?一方、jQuery はより実用的であり、その目標は単に記述を減らし、より多くのことを実行することです。

しかし、過激な理想主義者を待っている運命は、多くの場合、その野望が達成される前に死ぬことです。prototype.js の象徴的なバインド関数が ECMAScript 標準に吸収されたとき、そのオブジェクトのプロトタイプはどこでも変更され、その衰退は運命づけられました。これは、prototype.js の独自の秘技であり、そのアキレス腱でもあります。特に、jQuery を模倣して Element.extend(element) を介して拡張オブジェクトを返そうとすると、Prototype.js によって完全に捨てられます。 jQuery とは異なり、常にネイティブ オブジェクトのプロトタイプを直接変更します。ただし、ブラウザーはバグ、嘘、商業的陰謀に満ちた分野です。ネイティブ オブジェクト レベルで問題を解決すると、悲劇が起こることになります。問題、名前の競合、互換性の問題などは、ヘルプ ライブラリの機能では解決できないと言われています。Prototype.js のバージョン 2.0 は、大きな変更が加えられていると言われています。歴史を断ち切るか、互換性を放棄するかはわかりません。 、または亀裂の中で生き残るために苦労し続ける。

この記事が皆さんの jQuery プログラミングに役立つことを願っています。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。