jQuery 2.0.3 ソースコード解析コア (1) 全体アーキテクチャ_jquery

WBOY
リリース: 2016-05-16 16:46:40
オリジナル
1035 人が閲覧しました

オープンソース フレームワークについて読んだとき、最も学びたいのは、設計のアイデアと実装テクニックです。

それほどナンセンスではありません。jQuery 分析は長年にわたって悪影響を及ぼしてきました。私はずっと前に読んだことがあります。

しかし、ここ数年はモバイル端末で作業しており、常に zepto を使用していました。最近、時間をかけてもう一度 jquery をスキャンしました。

スクリプトに従ってソースコードを翻訳するわけではありませんので、実際の経験に基づいて読んでください。

github 上の最新のものは、AMD 仕様に加わった jquery-master です。公式の最新 2.0.3 を参照します。

全体構造

jQuery フレームワークの中核は、HTML ドキュメントの要素を照合し、それらの要素に対して操作を実行することです。

例:

コードをコピー コードは次のとおりです:

$().find().css ()
$().hide().html('....').hide().

上記の記述から少なくとも 2 つの問題が見つかります

1. jQuery オブジェクトの構築方法

2. jQueryメソッドの呼び出し方法

分析 1: jQuery の新規不要の構築

JavaScript は関数型言語であり、関数はクラスを実装できます。クラスはオブジェクト指向プログラミングの最も基本的な概念です。

コードをコピー コードは次のとおりです。

var aQuery = function(selector, context) {
//コンストラクター
}
aQuery.prototype = {
//プロトタイプ
name:function(){},
age:function(){}
}

var a = new aQuery();

a.name();

これは従来の使用方法であり、jQuery がこのように動作しないことは明らかです。

jQuery は、jQuery 表示のインスタンス化に new 演算子を使用しないか、その関数

を直接呼び出します。

jQueryの書き方に従う

コードをコピー コードは次のとおりです:

$().ready()
$( ).noConflict()

これを実現するには、jQuery をクラスとみなし、$() がクラスのインスタンスを返す必要があります

コードを変更します:

コードをコピー コードは次のとおりです。

var aQuery = function(selector, context) {
Return new aQuery();
}
aQuery.prototype = {
name:function(){},
age:function(){}
}

new aQuery() を使用すると、インスタンスが返されますが、無限ループという明らかな問題が依然として存在します。

では、正しいインスタンスを返すにはどうすればよいでしょうか?

JavaScript のインスタンス this はプロトタイプにのみ関連します

その後、jQuery クラスをファクトリ メソッドとして使用してインスタンスを作成し、このメソッドを jQuery.prototye プロトタイプに配置できます

コードをコピー コードは次のとおりです。

var aQuery = function(selector, context) {
return aQuery.prototype.init();
}
aQuery.prototype = {
init:function(){
return this;
}
name:function (){ },
age:function(){}
}

aQuery() の実行時に返されるインスタンス:

明らかに、aQuery() は aQuery クラスのインスタンスを返すため、init の this は実際には aQuery クラスのインスタンスを指します

問題は、init の this が aQuery クラスを指していることです。init 関数がコンストラクターとしても使用されている場合、内部の this をどのように処理すればよいでしょうか。

コードをコピー コードは次のとおりです。

var aQuery = function(selector, context) {
Return aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
},
名前: function() {},
年齢: 20
}

aQuery().age //18

この場合、これは aQuery クラスのみを指しているため、何か問題が発生します。そのため、独立したスコープを設計する必要があります

JQuery フレームワークの個別スコープ処理

コードをコピー コードは次のとおりです。

jQuery = function( selector, context ) {
// jQuery オブジェクトは実際には単なる init コンストラクター 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},

明らかに、インスタンス init 関数を通じて、これを分離し、相互作用の混乱を避けるために、毎回新しい init インスタンス オブジェクトが構築されます

したがって、これらは同じオブジェクトではないため、新たな問題が発生するはずです

例:

コードをコピー コードは次のとおりです。

var aQuery = function(selector, context) {
Return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
} ,
名前: function() {},
年齢: 20
}

//Uncaught TypeError: オブジェクト [object Object] にはメソッド 'name' がありません
console.log(aQuery().name())

エラーがスローされ、このメソッドが見つからないため、new の init が jquery クラスの this から分離されていることは明らかです

jQuery クラス プロトタイプのプロパティとメソッドにアクセスするにはどうすればよいですか?

スコープを分離するだけでなく、jQuery プロトタイプ オブジェクトのスコープを使用するにはどうすればよいですか?

返されたインスタンス内の jQuery プロトタイプ オブジェクトにもアクセスできますか?

実装の重要なポイント

コードをコピー コードは次のとおりです:

// init 関数に jQuery プロトタイプを与えます後のインスタンス化のために
jQuery.fn.init.prototype = jQuery.fn;

プロトタイプを渡すことで問題を解決し、jQuery プロトタイプを jQuery.prototype.init.prototype に渡します

言い換えると、jQuery のプロトタイプ オブジェクトは、init コンストラクターのプロトタイプ オブジェクトをオーバーライドします

参照によって渡されるため、この循環参照のパフォーマンスの問題を心配する必要はありません

コードをコピー コードは次のとおりです。

var aQuery = function(selector, context) {
return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
return this;
},
name : function( ) {
return this.age
},
age: 20
}
aQuery.prototype.init.prototype = aQuery.prototype;
console.log(aQuery ().名前()) //20

Baidu は、簡単かつ直接的に理解できるよう、ネチズンから画像を借用しました:

fn について説明します。実際、この fn には特別な意味はなく、単なる jQuery.prototype への参照です

分析 2: チェーンコール

DOM チェーン呼び出しの処理:

1. JS コードを保存します。

2. 同じオブジェクトが返されるため、コードの効率が向上します

プロトタイプ メソッドを拡張してこれを返すだけで、クロスブラウザー チェーン呼び出しを実現できます。

JS で単純なファクトリ パターンを使用して、同じ DOM オブジェクトに対するすべての操作に対して同じインスタンスを指定します。

この原則は非常にシンプルです

コードをコピー コードは次のとおりです:

aQuery().init().name ()
分解
a = aQuery();
a.init()
a.name()

コードを分解すると、チェーンを実現するための基本的な条件はインスタンス this の存在であり、それは同じであることがわかります。

コードをコピー コードは次のとおりです。

aQuery.prototype = {
init : function( ) {
これを返す;
},
name: function() {
これを返す
}
}

したがって、連鎖メソッドでこれにアクセスするだけで済みます。これは、現在のインスタンスの this を返すため、独自のプロトタイプにアクセスできます

コードをコピー コードは次のとおりです:

aQuery.init().name()

利点: コードの量を節約し、コードの効率を向上させ、コードの見た目がよりエレガントになります

最悪の点は、すべてのオブジェクト メソッドがオブジェクト自体を返すことです。これは戻り値がないことを意味しており、これはどの環境にも適さない可能性があります。

JavaScript はノンブロッキング言語であるため、ブロッキングはしませんが、ブロックすることはできません。そのため、イベントによって駆動され、プロセスをブロックする必要がある一部の操作を非同期で完了する必要があります。この処理は単なる同期チェーンです。非同期チェーン jquery Promise は 1.5 から導入されており、jQuery.Deferred については後で説明します。

分析 3: プラグイン インターフェイス

jQuery の主なフレームワークは次のとおりですが、一般的なデザイナーの習慣によれば、jQuery または jQuery プロトタイプに属性メソッドを追加する場合、および開発者にメソッド拡張を提供する場合は、カプセル化の観点から見ると、インターフェイスは正しいものであり、フレンドリーなユーザー インターフェイスを直接変更するのではなく、文字通りに理解できます。

jQuery は独自の拡張プロパティをサポートし、オブジェクトにメソッドを追加するための外部インターフェイス jQuery.fn.extend() を提供します。

jQuery ソース コードからわかるように、jQuery.extend と jQuery.fn.extend は実際には同じメソッドを指す異なる参照です

コードをコピー コードは次のとおりです。
jQuery.extend = jQuery.fn.extend = function( ) {
jQuery.extend は jQuery 自体のプロパティとメソッドを拡張します

jQuery.fn.extend は、jQuery.fn


のプロパティとメソッドを拡張します。 extend() 関数を使用すると、jQuery のプロトタイプ構造を破壊することなく、関数を簡単かつ迅速に拡張できます

jQuery.extend = jQuery.fn.extend = function(){...}; これは連続しています、つまり、同じ関数を指している 2 つの点ですが、どのようにして異なる関数を実現できるのでしょうか?これがこの力だ!

前に説明したように、Fn と jQuery は実際には 2 つの異なるオブジェクトです。

jQuery.extend が呼び出されると、これは jQuery オブジェクト (jQuery は関数でありオブジェクトです!) を指すため、ここでの拡張は jQuery 上にあります。

jQuery.fn.extend が呼び出されるとき、これは fn オブジェクトを指し、jQuery.fn と jQuery.prototype は同じオブジェクトを指します。fn を拡張すると、jQuery.prototype プロトタイプ オブジェクトが拡張されます。
ここで追加するのがプロトタイプメソッド、つまりオブジェクトメソッドです。そこで、jQuery APIでは上記2つの拡張機能を提供しています。

拡張の実装

コードをコピー コードは次のとおりです:

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},    // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    // 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况
        deep = target;  // 此时target是true
        target = arguments[1] || {};    // target改为 obj1
        // skip the boolean and the target
        i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {   // 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )
        target = this;  // jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn
        --i;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy ) {    // 防止自引用,不赘述
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                // 如果是深拷贝,且被拷贝的属性值本身是个对象
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {    // 被拷贝的属性值是个数组
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {    被拷贝的属性值是个plainObject,比如{ nick: 'casper' }
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

// 元のオブジェクトは決して移動せず、クローンを作成してください
Target [name] = jquery.extEnd (deep, clone, copy) // 再帰 ~

}
}
}
}

// 変更されたオブジェクトを返します
return target;



概要:

init コンストラクターのプロトタイプ プロトタイプ オブジェクト メソッドを使用して、new jQuery.fn.init() を通じて新しいオブジェクトを構築します。

プロトタイプ ポインターのポインティングを変更することで、この新しいオブジェクトがプロトタイプのプロトタイプも指すようにします。 jQuery クラスのプロトタイプ

したがって、この方法で構築されたオブジェクトは、jQuery.fn プロトタイプ

で定義されたすべてのメソッドを継続します。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!