亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

jquery的總體架構分析及實現示例詳解

2019-11-20 13:56:42
字體:
來源:轉載
供稿:網友

jQuery整體框架甚是復雜,也不易讀懂,這幾日一直在研究這個笨重而強大的框架。jQuery的總體架構可以分為:入口模塊、底層模塊和功能模塊。這里,我們以jquery-1.7.1為例進行分析。

jquery的總體架構

復制代碼 代碼如下:

16 (function( window, undefined ) {
         // 構造 jQuery 對象
  22     var jQuery = (function() {
  25         var jQuery = function( selector, context ) {
  27                 return new jQuery.fn.init( selector, context, rootjQuery );
  28             },
                 // 一堆局部變量聲明
  97         jQuery.fn = jQuery.prototype = {
  98             constructor: jQuery,
  99             init: function( selector, context, rootjQuery ) { ... },
                 // 一堆原型屬性和方法
 319         };
 322         jQuery.fn.init.prototype = jQuery.fn;
 324         jQuery.extend = jQuery.fn.extend = function() { ... };
 388         jQuery.extend({
                 // 一堆靜態屬性和方法
 892         });
 955         return jQuery;
 957     })();
          // 省略其他模塊的代碼 ...
9246     window.jQuery = window.$ = jQuery;
9266 })( window );

分析一下以上代碼,我們發現jquery采取了匿名函數自執行的寫法,這樣做的好處就是可以有效的防止命名空間與變量污染的問題。縮寫一下以上代碼就是:

復制代碼 代碼如下:

(function(window, undefined) {
    var jQuery = function() {}
    // ...
    window.jQuery = window.$ = jQuery;
})(window);

參數window

匿名函數傳了兩個參數進來,一個是window,一個是undefined。我們知道,在js中變量是有作用域鏈的,這兩個變量的傳入就會變成匿名函數的局部變量,訪問起來的時候速度會更快。通過傳入window對象可以使window對象作為局部變量使用,那么,函數的參數也都變成了局部變量,當在jquery中訪問window對象時,就不需要將作用域鏈退回到頂層作用域,從而可以更快的訪問window對象。

參數undefined

js在查找變量的時候,js引擎首先會在函數自身的作用域中查找這個變量,如果沒有的話就繼續往上找,找到了就返回該變量,找不到就返回undefined。undefined是window對象的一個屬性,通過傳入undefined參數,但又不進行賦值,可以縮短查找undefined時的作用域鏈。在 自調用匿名函數 的作用域內,確保undefined是真的未定義。因為undefined能夠被重寫,賦予新的值。

jquery.fn是啥?

復制代碼 代碼如下:

 jQuery.fn = jQuery.prototype = {
              constructor: jQuery,
              init: function( selector, context, rootjQuery ) { ... },
                 // 一堆原型屬性和方法
        };

通過分析以上代碼,我們發現jQuery.fn即是jQuery.prototype,這樣寫的好處就是更加簡短吧。之后,我們又看到jquery為了簡潔,干脆使用一個$符號來代替jquery使用,因此,在我們使用jquery框架的使用經常都會用到$(),

構造函數jQuery()

圖片描述

jQuery的對象并不是通過 new jQuery 創建的,而是通過 new jQuery.fn.init 創建的:

復制代碼 代碼如下:

var jQuery = function( selector, context ) {

       return new jQuery.fn.init( selector, context, rootjQuery );

}

這里定義了一個變量jQuery,他的值是jQuery構造函數,在955行(最上面的代碼)返回并賦值給jQuery變量

jQuery.fn.init

jQuery.fn (上面97行)是構造函數jQuery()的原型對象,jQuery.fn.init()是jQuery原型方法,也可以稱作構造函數。負責解析參數selector和context的類型并執行相應的查找。

參數context:可以不傳入,或者傳入jQuery對象,DOM元素,普通js對象之一
參數rootjQuery:包含了document對象的jQuery對象,用于document.getElementById()查找失敗等情況。

復制代碼 代碼如下:

jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
jQuery(selector [,context])

默認情況下,對匹配元素的查找從根元素document 對象開始,即查找范圍是整個文檔樹,不過也可以傳入第二個參數context來限定它的查找范圍。例如:

復制代碼 代碼如下:

$('div.foo').click(function () {
            $('span',this).addClass('bar');//限定查找范圍,即上面的context
   });
jQuery.extend()和jQuery.fn.extend()

方法jQuery.extend(object)和jQuery.fn.extend(object)用于合并兩個或多個對象到第一個對象。相關源代碼如下(部分):

復制代碼 代碼如下:

jQuery.extend = jQuery.fn.extend = function() {
    var options, name, src, copy, copyIsArray, clone,//定義的一組局部變量
        target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false;

jQuery.extend(object); 為jQuery類添加添加類方法,可以理解為添加靜態方法。如:

復制代碼 代碼如下:

$.extend({
  add:function(a,b){returna+b;}
});

便為 jQuery 添加一個為add 的 “靜態方法”,之后便可以在引入 jQuery 的地方,使用這個方法了,

$.add(3,4); //return 7
jQuery.fn.extend(object),查看一段官網的代碼演示如下:

復制代碼 代碼如下:

<label><input type="checkbox" name="foo"> Foo</label>
<label><input type="checkbox" name="bar"> Bar</label>

<script>
    jQuery.fn.extend({
        check: function() {
            return this.each(function() {
                this.checked = true;
            });
        },
        uncheck: function() {
            return this.each(function() {
                this.checked = false;
            });
        }
    });
    // Use the newly created .check() method
    $( "input[type='checkbox']" ).check();
</script>

CSS選擇器引擎 Sizzle

可以說,jQuery是為操作DOM而誕生的,jQuery之所以如此強大,得益于CSS選擇器引擎 Sizzle,解析規則引用網上的一段實例:

selector:"div > p + div.aaron input[type="checkbox"]"

解析規則:
1 按照從右到左
2 取出最后一個token  比如[type="checkbox"]
                            {
                                matches : Array[3]
                                type    : "ATTR"
                                value   : "[type="
                                checkbox "]"
                            }
3 過濾類型 如果type是 > + ~ 空 四種關系選擇器中的一種,則跳過,在繼續過濾
4 直到匹配到為 ID,CLASS,TAG  中一種 , 因為這樣才能通過瀏覽器的接口索取
5 此時seed種子合集中就有值了,這樣把刷選的條件給縮的很小了
6 如果匹配的seed的合集有多個就需要進一步的過濾了,修正選擇器 selector: "div > p + div.aaron [type="checkbox"]"
7 OK,跳到一下階段的編譯函數

deferred對象

開發網站的過程中,我們經常遇到某些耗時很長的javascript操作。其中,既有異步的操作(比如ajax讀取服務器數據),也有同步的操作(比如遍歷一個大型數組),它們都不是立即能得到結果的。

通常的做法是,為它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。

但是,在回調函數方面,jQuery的功能非常弱。為了改變這一點,jQuery開發團隊就設計了deferred對象。

簡單說,deferred對象就是jQuery的回調函數解決方案。在英語中,defer的意思是"延遲",所以deferred對象的含義就是"延遲"到未來某個點再執行。

回顧一下jQuery的ajax操作的傳統寫法:

復制代碼 代碼如下:

$.ajax({
   url: "test.html",
   success: function(){
     alert("哈哈,成功了!");
   },
   error:function(){
     alert("出錯啦!");
   }
 });

在上面的代碼中,$.ajax()接受一個對象參數,這個對象包含兩個方法:success方法指定操作成功后的回調函數,error方法指定操作失敗后的回調函數。

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR對象,你沒法進行鏈式操作;如果高于1.5.0版本,返回的是deferred對象,可以進行鏈式操作。

現在,新的寫法是這樣的:

復制代碼 代碼如下:

$.ajax("test.html")
  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出錯啦!"); });

為多個操作指定回調函數

deferred對象的另一大好處,就是它允許你為多個事件指定一個回調函數,這是傳統寫法做不到的。

請看下面的代碼,它用到了一個新的方法$.when():

復制代碼 代碼如下:

$.when($.ajax("test1.html"), $.ajax("test2.html"))

 .done(function(){ alert("哈哈,成功了!"); })

 .fail(function(){ alert("出錯啦!"); });

這段代碼的意思是,先執行兩個操作$.ajax("test1.html")和$.ajax("test2.html"),如果都成功了,就運行done()指定的回調函數;如果有一個失敗或都失敗了,就執行fail()指定的回調函數。

jQuery.Deferred( func ) 的實現原理

內部維護了三個回調函數列表:成功回調函數列表、失敗回調函數列表、消息回調函數列表,其他方法則圍繞這三個列表進行操作和檢測。

jQuery.Deferred( func ) 的源碼結構:

復制代碼 代碼如下:

 jQuery.extend({

    Deferred: function( func ) {
            // 成功回調函數列表
        var doneList = jQuery.Callbacks( "once memory" ),
            // 失敗回調函數列表
            failList = jQuery.Callbacks( "once memory" ),
            // 消息回調函數列表
            progressList = jQuery.Callbacks( "memory" ),
            // 初始狀態
            state = "pending",
            // 異步隊列的只讀副本
            promise = {
                // done, fail, progress
                // state, isResolved, isRejected
                // then, always
                // pipe
                // promise          
            },
            // 異步隊列
            deferred = promise.promise({}),
            key;
        // 添加觸發成功、失敗、消息回調函列表的方法
        for ( key in lists ) {
            deferred[ key ] = lists[ key ].fire;
            deferred[ key + "With" ] = lists[ key ].fireWith;
        }
        // 添加設置狀態的回調函數
        deferred.done( function() {
            state = "resolved";
        }, failList.disable, progressList.lock )
        .fail( function() {
            state = "rejected";
        }, doneList.disable, progressList.lock );
        // 如果傳入函數參數 func,則執行。
        if ( func ) {
            func.call( deferred, deferred );
        }

        // 返回異步隊列 deferred
        return deferred;
    },
}

jQuery.when( deferreds )

提供了基于一個或多個對象的狀態來執行回調函數的功能,通常是基于具有異步事件的異步隊列。

jQuery.when( deferreds ) 的用法

如果傳入多個異步隊列對象,方法 jQuery.when() 返回一個新的主異步隊列對象的只讀副本,只讀副本將跟蹤所傳入的異步隊列的最終狀態。

一旦所有異步隊列都變為成功狀態,“主“異步隊列的成功回調函數被調用;

如果其中一個異步隊列變為失敗狀態,主異步隊列的失敗回調函數被調用。

復制代碼 代碼如下:

/*
請求 '/when.do?method=when1' 返回 {"when":1}
請求 '/when.do?method=when2' 返回 {"when":2}
請求 '/when.do?method=when3' 返回 {"when":3}
*/
var whenDone = function(){ console.log( 'done', arguments ); },
    whenFail = function(){ console.log( 'fail', arguments ); };
$.when(
    $.ajax( '/when.do?method=when1', { dataType: "json" } ),
    $.ajax( '/when.do?method=when2', { dataType: "json" } ),
    $.ajax( '/when.do?method=when3', { dataType: "json" } )
).done( whenDone ).fail( whenFail );

圖片描述

異步隊列 Deferred

解耦異步任務和回調函數

為 ajax 模塊、隊列模塊、ready 事件提供基礎功能。

原型屬性和方法

原型屬性和方法源代碼:

復制代碼 代碼如下:

  97 jQuery.fn = jQuery.prototype = {
  98     constructor: jQuery,
  99     init: function( selector, context, rootjQuery ) {}
 210     selector: "",
 213     jquery: "1.7.1",
 216     length: 0,
 219     size: function() {},
 223     toArray: function() {},
 229     get: function( num ) {},
 241     pushStack: function( elems, name, selector ) {},
 270     each: function( callback, args ) {},
 274     ready: function( fn ) {}, //
 284     eq: function( i ) {},
 291     first: function() {},
 295     last: function() {},
 299     slice: function() {},
 304     map: function( callback ) {},
 310     end: function() {},
 316     push: push,
 317     sort: [].sort,
 318     splice: [].splice
 319 };
 

屬性selector用于記錄jQuery查找和過濾DOM元素時的選擇器表達式。
屬性.length表示當前jquery對象中元素的個數。
方法.size()返回當前jquery對象中元素的個數,功能上等同于屬性length,但應該優先使用length,因為他沒有函數調用開銷。

.size()源碼如下:

復制代碼 代碼如下:

size():function(){
    return this.length;
}

方法.toArray()將當前jQuery對象轉換為真正的數組,轉換后的數組包含了所有元素,其源碼如下:

復制代碼 代碼如下:

toArray: function() {
        return slice.call( this );
    },

方法.get(index)返回當前jQuery對象中指定位置的元素,或包含了全部元素的數組。其源
碼如下:

復制代碼 代碼如下:

    get: function( num ) {
        return num == null ?

            // Return a 'clean' array
            this.toArray() :

            // Return just the object
            ( num < 0 ? this[ this.length + num ] : this[ num ] );
    },


如果沒有傳入參數,則調用.toArray()返回了包含有鎖元素的數組;如果指定了參數index,則返回一個單獨的元素,index從0開始計數,并且支持負數。

首先會判斷num是否小于0,如果小于0,則用length+num重新計算下標,然后使用數組訪問操作符([])獲取指定位置的元素,這是支持下標為負數的一個小技巧;如果大于等于0,直接返回指定位置的元素。

eg()和get()使用詳解jquery常用方法及使用示例匯總

方法.each()用于遍歷當前jQuery對象,并在每個元素上執行回調函數。方法.each()內部通過簡單的調用靜態方法jQuery.each()實現:

復制代碼 代碼如下:

each: function( callback, args ) {
        return jQuery.each( this, callback, args );
    },

回調函數是在當前元素為上下文的語境中觸發的,即關鍵字this總是指向當前元素,在回調函數中return false 可以終止遍歷。

方法.map()遍歷當前jQuery對象,在每個元素上執行回調函數,并將回調函數的返回值放入一個新jQuery對象中。該方法常用于獲取或設置DOM元素集合的值。

復制代碼 代碼如下:

map: function( callback ) {
        return this.pushStack( jQuery.map(this, function( elem, i ) {
            return callback.call( elem, i, elem );
        }));
    },

原型方法.pushStack()創建一個新的空jQuery對象,然后把DOM元素集合放入這個jQuery對象中,并保留對當前jQuery對象的引用。

原型方法.pushStack()是核心方法之一,它為以下方法提供支持:

jQuery對象遍歷:.eq()、.first()、.last()、.slice()、.map()。

DOM查找、過濾:.find()、.not()、.filter()、.closest()、.add()、.andSelf()。

DOM遍歷:.parent()、.parents()、.parentsUntil()、.next()、.prev()、.nextAll()、.prevAll()、.nextUnit()、.prevUnit()、.siblings()、.children()、.contents()。

DOM插入:jQuery.before()、jQuery.after()、jQuery.replaceWith()、.append()、.prepent()、.before()、.after()、.replaceWith()。
定義方法.push( elems, name, selector ),它接受3個參數:

參數elems:將放入新jQuery對象的元素數組(或類數組對象)。

參數name:產生元素數組elems的jQuery方法名。

參數selector:傳給jQuery方法的參數,用于修正原型屬性.selector。
方法.end()結束當前鏈條中最近的篩選操作,并將匹配元素還原為之前的狀態

復制代碼 代碼如下:

end: function() {
        return this.prevObject || this.constructor(null);
    },

返回前一個jQuery對象,如果屬性prevObect不存在,則構建一個空的jQuery對象返回。方法.pushStack()用于入棧,方法.end()用于出棧

靜態屬性和方法

相關源碼如下:

復制代碼 代碼如下:

388 jQuery.extend({
 389     noConflict: function( deep ) {},
 402     isReady: false,
 406     readyWait: 1,
 409     holdReady: function( hold ) {},
 418     ready: function( wait ) {},
 444     bindReady: function() {},
 492     isFunction: function( obj ) {},
 496     isArray: Array.isArray || function( obj ) {},
 501     isWindow: function( obj ) {},
 505     isNumeric: function( obj ) {},
 509     type: function( obj ) {},
 515     isPlainObject: function( obj ) {},
 544     isEmptyObject: function( obj ) {},
 551     error: function( msg ) {},
 555     parseJSON: function( data ) {},
 581     parseXML: function( data ) {},
 601     noop: function() {},
 606     globalEval: function( data ) {},
 619     camelCase: function( string ) {},
 623     nodeName: function( elem, name ) {},
 628     each: function( object, callback, args ) {},
 669     trim: trim ? function( text ) {} : function( text ) {},
 684     makeArray: function( array, results ) {},
 702     inArray: function( elem, array, i ) {},
 724     merge: function( first, second ) {},
 744     grep: function( elems, callback, inv ) {},
 761     map: function( elems, callback, arg ) {},
 794     guid: 1,
 798     proxy: function( fn, context ) {},
 825     access: function( elems, key, value, exec, fn, pass ) {},
 852     now: function() {},
 858     uaMatch: function( ua ) {},
 870     sub: function() {},
 891     browser: {}
 892 });
 

未完待續、、、今天就先到這里了,下次補齊。別急哈小伙伴們

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产成人精品a视频一区www| 成人有码在线播放| 久久人人爽人人爽人人片av高清| 亚洲精品成a人在线观看| 亚洲色无码播放| 国产在线高清精品| 疯狂蹂躏欧美一区二区精品| 国产成人精品亚洲精品| 亚洲欧洲激情在线| 精品爽片免费看久久| 国产欧美日韩亚洲精品| 国产精品盗摄久久久| 91精品久久久久久久久| 日韩精品丝袜在线| 国产成人精品在线观看| 在线看国产精品| 亚洲女人天堂av| 亚洲精品v欧美精品v日韩精品| 国产精品亚洲欧美导航| 日本精品免费观看| 久久国产精品久久国产精品| 欧美极品少妇xxxxⅹ免费视频| 日韩精品在线电影| 在线播放国产一区中文字幕剧情欧美| 97精品一区二区三区| 国产综合久久久久久| 国产精品专区一| 综合激情国产一区| 亚洲一区免费网站| 久久精品视频在线播放| 97视频免费观看| 亚洲欧美国产高清va在线播| 欧美一区二区大胆人体摄影专业网站| 久久久精品亚洲| 亚洲 日韩 国产第一| 日韩亚洲国产中文字幕| 日韩激情av在线播放| 午夜精品久久久久久99热软件| 丝袜情趣国产精品| 国产精品电影一区| 黄色一区二区三区| 亚洲japanese制服美女| 色偷偷av一区二区三区乱| 亚洲成人av资源网| 亚洲电影中文字幕| 国产中文字幕亚洲| 国产一区二区三区中文| 亚州精品天堂中文字幕| 日av在线播放中文不卡| 亚洲mm色国产网站| 久久久久久久久中文字幕| 日韩av一卡二卡| 色妞一区二区三区| 精品国产福利在线| 色噜噜国产精品视频一区二区| 4438全国亚洲精品在线观看视频| 热久久这里只有精品| 欧美精品18videos性欧美| 欧美亚洲在线视频| 一道本无吗dⅴd在线播放一区| 欧美日韩在线免费| 一区二区三区四区在线观看视频| 亚洲美女激情视频| 亚洲福利在线看| 久久精品亚洲94久久精品| 17婷婷久久www| 国外日韩电影在线观看| 国产亚洲精品综合一区91| 国产女精品视频网站免费| 国产精品尤物福利片在线观看| 韩国日本不卡在线| 国产精品视频一区国模私拍| 91精品国产成人www| 欧美日韩美女在线| 91精品久久久久久久久青青| 国产精品入口日韩视频大尺度| 中文字幕精品一区二区精品| 国产精品久久久久久网站| 欧美小视频在线观看| 亚洲天堂网在线观看| 97视频在线播放| 日韩精品极品在线观看| 在线播放精品一区二区三区| 亚洲精品久久久久中文字幕二区| 亚洲精品午夜精品| 中文字幕一区二区精品| 91精品在线国产| 91免费视频网站| 精品日本高清在线播放| 欧美一性一乱一交一视频| 国产精品久久久久久久一区探花| 97超级碰碰碰久久久| 日本不卡免费高清视频| 黑人精品xxx一区一二区| 日产精品久久久一区二区福利| 欧美性色视频在线| 高清欧美电影在线| 成人精品一区二区三区电影黑人| 日韩成人高清在线| 77777少妇光屁股久久一区| 久久天天躁日日躁| 欧美激情一区二区久久久| 97av在线影院| 国产91在线播放九色快色| 日韩精品中文字幕有码专区| 777精品视频| 欧美乱大交xxxxx| 日韩av电影院| 性欧美亚洲xxxx乳在线观看| 亚洲第一精品夜夜躁人人躁| 亚洲一区中文字幕在线观看| 国内精品久久久久久中文字幕| 欧美激情第99页| 亚洲一区二区三区xxx视频| 国产精品精品一区二区三区午夜版| 亚洲aⅴ男人的天堂在线观看| 国产精品综合不卡av| 亚洲精品国产suv| 成人伊人精品色xxxx视频| 中文国产亚洲喷潮| 国产精品美女久久久久av超清| 日韩中文字幕在线播放| 成人午夜两性视频| 欧美一级淫片videoshd| 欧美视频13p| 久久99久久久久久久噜噜| 中文字幕久热精品视频在线| 91精品啪aⅴ在线观看国产| 亚洲aⅴ男人的天堂在线观看| 欧洲精品在线视频| 51久久精品夜色国产麻豆| 久久精品青青大伊人av| 欧美精品久久久久久久| 日韩精品中文字幕久久臀| 好吊成人免视频| 亚洲一区中文字幕在线观看| 亚洲欧美日韩一区在线| 欧美激情亚洲综合一区| 国产精品电影一区| 亚洲sss综合天堂久久| 国产精品高潮呻吟久久av野狼| 亚洲人成网在线播放| 国产精品伦子伦免费视频| 在线观看欧美日韩国产| 九九综合九九综合| 欧美日韩国产限制| 日av在线播放中文不卡| 97在线精品国自产拍中文| 亚洲一区二区三区四区视频| 日本亚洲欧洲色| 红桃av永久久久| 亚洲美女在线视频| 亚洲国产欧美一区二区三区同亚洲| 亚洲国产成人精品久久久国产成人一区| 国产福利视频一区二区| 久久99精品久久久久久噜噜| 久久福利视频导航| 亚洲精品视频二区| 亚洲精品久久7777777| 2023亚洲男人天堂| 国内精品久久影院| 欲色天天网综合久久| 国产精品扒开腿做爽爽爽的视频| 91精品国产色综合久久不卡98口|