最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識(shí)百科 - 正文

jQuery1.5源碼解讀面向中高階JSER_jquery

來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 20:58:45
文檔

jQuery1.5源碼解讀面向中高階JSER_jquery

jQuery1.5源碼解讀面向中高階JSER_jquery:幾乎很難從jQuery分離其中的一部分功能。所以在這里我分享下應(yīng)該讀 jQuery 源碼的一些成果,以及讀源碼的方法??写a是必須的。 1. 代碼折疊是必須的。 因此必須在支持語法折疊的編輯器里打開源碼。 根據(jù)折疊層次,我們可以很快知道: 所有 jQuery 的
推薦度:
導(dǎo)讀jQuery1.5源碼解讀面向中高階JSER_jquery:幾乎很難從jQuery分離其中的一部分功能。所以在這里我分享下應(yīng)該讀 jQuery 源碼的一些成果,以及讀源碼的方法??写a是必須的。 1. 代碼折疊是必須的。 因此必須在支持語法折疊的編輯器里打開源碼。 根據(jù)折疊層次,我們可以很快知道: 所有 jQuery 的

幾乎很難從jQuery分離其中的一部分功能。所以在這里我分享下應(yīng)該讀 jQuery 源碼的一些成果,以及讀源碼的方法。啃代碼是必須的。

1. 代碼折疊是必須的。

因此必須在支持語法折疊的編輯器里打開源碼。 根據(jù)折疊層次,我們可以很快知道: 所有 jQuery 的代碼都在一個(gè)函數(shù)中:   

(function( window, undefined ) {
// jQuery 代碼

})(window);

這樣可以避免內(nèi)部對(duì)象污染全局。傳入的參數(shù)1是 window, 參數(shù)2是 undefined , 加快js搜索此二對(duì)象的速度。

2. 接著打開第一級(jí)折疊。

可以發(fā)現(xiàn) jQuery 代碼是按這樣順序來組織:

  • 定義 jQuery 函數(shù) ( 代碼 20 - 1081 行)
  • 生成 jQuery.support (代碼 1083 - 1276 行)
  • 和 data 有關(guān)擴(kuò)展 (代碼 1279 - 1510 行)
  • 和隊(duì)列有關(guān)擴(kuò)展 (代碼 1514 - 1605 行)
  • 和屬性有關(guān)擴(kuò)展 (代碼 1609 - 1988 行)
  • 和事件有關(guān)擴(kuò)展 (代碼 1993 - 3175 行)
  • 內(nèi)部的Sizzle CSS Selector Engine (代碼 3183 - 4518 行)
  • 和節(jié)點(diǎn)有關(guān)擴(kuò)展 (代碼 4520 - 5492 行)
  • 和樣式有關(guān)擴(kuò)展 (代碼 5497 - 5825 行)
  • 和ajax有關(guān)擴(kuò)展 (代碼 5830 - 7172 行)
  • 和效果有關(guān)擴(kuò)展 (代碼 7176 - 7696 行)
  • 和定位有關(guān)擴(kuò)展 (代碼 7700 - 8065 行)
  • 下面的模塊可以用上面的模塊,上面的模塊不需要下面的模塊

    3. 定義 jQuery 函數(shù) ( 代碼 20 - 1081 行)

    總的代碼是這樣的框架:

    var jQuery = (function() {
    // 創(chuàng)建 jQuery 對(duì)象
    var jQuery = function( selector, context ) {
    // 略

    };

    // 創(chuàng)建 jQuery.fn 對(duì)象
    jQuery.fn = jQuery.prototype = {
    // 略
    };

    // 聲明 jQuery.extend
    jQuery.extend = jQuery.fn.extend = function() {
    // 略
    };

    // 使用 jQuery.extend 擴(kuò)展自己
    jQuery.extend({
    // 略

    });

    // 瀏覽器方面的一些瑣碎
    // 略

    // 定義全局對(duì)象
    return (window.jQuery = window.$ = jQuery);

    })();

    從這里知道: 平時(shí)所用的 $ 其實(shí)就是 jQuery 函數(shù)的別名。

    3.1 jQuery對(duì)象 (代碼 23 - 26 行)

    jQuery對(duì)象似乎一直都是這東西:

    var jQuery = function( selector, context ) {
    // 實(shí)際上 jQuery 對(duì)象是 jQuery.fn.init 返回的。
    return new jQuery.fn.init( selector, context, rootjQuery );
    }

    這個(gè)函數(shù)表示: 要想知道函數(shù) jQuery 是什么東西,必須看 jQuery.fn.init 對(duì)象。

    同時(shí)這也解釋了為什么寫代碼不需要 new jQuery。

    再看第29行 - 97行, 都是一些變量聲明,這些變量在下面的函數(shù)用到。提取變量的好處: 對(duì)正則節(jié)約編譯的時(shí)間, 同時(shí)能在壓縮的時(shí)候獲得更小的結(jié)果。

    3.2 jQuery.fn 對(duì)象 (代碼 99 - 320 行)

    這個(gè)fn 其實(shí)是 jQuery.prototype ,這也是為啥jQuery.fn 就是擴(kuò)展 jQuery對(duì)象的唯一原因。

    肯能有人會(huì)疑問, jQuery 返回 new jQuery.fn.init, 也就是說,平時(shí)的函數(shù)應(yīng)該是 jQuery.fn.init.prototype 所有的成員,不是 jQuery.prototype 成員。當(dāng)然原因也很簡單: jQuery.fn.init.prototype === jQuery.prototype (代碼 322 行)

    jQuery 對(duì)js對(duì)象處理和中國人講話一樣繞。這里總結(jié)下到底 jQuery 對(duì)象是個(gè)什么家伙。

    jQuery 是普通函數(shù), 返回 jQuery.fn.init 對(duì)象的實(shí)例( new jQuery.fn.init() )。

    然后 jQuery.fn === jQuery.prototype === jQuery.fn.init.prototype ,最后, jQuery返回的對(duì)象的成員和 jQuery.fn 的成員匹配。

    jQuery.fn 下有很多成員,下面稍作介紹:

    init - 初始化(下詳細(xì)說明)

    constructor - 手動(dòng)指定一個(gè)構(gòu)造函數(shù)。 因?yàn)槟J(rèn)是 jQuery.fn.init

    length - 讓這個(gè)對(duì)象更接近一個(gè) 原生的數(shù)組

    size - 返回 length

    toArray - 通過 Array.prototype slice 實(shí)現(xiàn)生成數(shù)組

    get - 即 this[ num ] ,當(dāng)然作了下 參數(shù)索引 的處理。

    pushStack - 加入一個(gè)元素

    ready - 瀏覽器加載后執(zhí)行(下詳細(xì)說明)

    end - 通過保存的 prevObject 重新返回

    each - 參考 http://www.cnblogs.com/Fooo/archive/2011/01/11/1932900.html

    參考 http://www.cnblogs.com/rubylouvre/archive/2009/11/21/1607632.html

    3.3 jQuery.fn.init (代碼 101 - 211 行)

    jQuery.fn.init 就是所謂的 $ 函數(shù)。 也就是說,平常的 $("#id") 就是 new jQuery.fn.init("#id");

    這個(gè)函數(shù)很長,但代碼覆蓋率小。

     init: function( selector, context, rootjQuery ) {
    // 參數(shù): selector 選擇器
    // context 上下文
    // rootjQuery 父節(jié)點(diǎn)

    // 處理 $("")、 $(null) 和 $(undefined)
    if ( !selector ) {
    return this;
    }

    // 處理 $(DOMElement)
    if ( selector.nodeType ) {

    // 直接扔數(shù)組中, 就搞定了。
    this.context = this[0] = selector;
    this.length = 1;
    return this;
    }

    // 處理 $("body") body 元素只存在一次,單獨(dú)找它
    if ( selector === "body" && !context && document.body ) {

    // 同樣扔數(shù)組中, 順便把 selector 更新更新。
    this.context = document;
    this[0] = document.body;
    thisis.selector = "body";
    this.length = 1;
    return this;
    }

    // 處理 $(HTML 代碼 或者是 css 選擇器)
    if ( typeof selector === "string" ) {
    // 略

    // 處理 $(函數(shù))
    } else if ( jQuery.isFunction( selector ) ) {

    // 如果是函數(shù),則執(zhí)行 $(document).ready , 這樣 $(document).ready(func) 簡為 $(func)
    return rootjQuery.ready( selector );
    }

    // 略。

    // 如果傳入的是一個(gè) Dom列表 ( getElementsByTagName 結(jié)果 ) 則轉(zhuǎn)為 jQuery 數(shù)組。
    return jQuery.makeArray( selector, this );
    }

    // 這部分代碼是 上段中 略 的 也就是說是 jQuery(字符串) 處理。

    // 檢查是否字符串是常用選擇器 (/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/)
    match = quickExpr.exec( selector );

    // 檢查是否正確匹配
    if ( match && (match[1] || !context) ) {

    // 處理: $(html) -> $(array)
    if ( match[1] ) {

    // 獲取正文,默認(rèn) document
    context = context instanceof jQuery ? context[0] : context;
    doc = (context ? context.ownerDocument || context : document);

    // 如果傳入簡單的 "<標(biāo)簽>", ( /^<(\w+)\s*\/?>(?:<\/\1>)?$/)
    ret = rsingleTag.exec( selector );

    // 返回 createElement("tag")

    return jQuery.merge( this, selector );

    // 處理: $("#id")
    } else {
    elem = document.getElementById( match[2] );

    // 因?yàn)橛械臑g覽器 getElementById 不只返回 id匹配的,所以做檢查。
    return this;
    }

    // 處理 $("標(biāo)簽")
    } else if ( !context && !rnonword.test( selector ) ) {
    this.selector = selector;
    this.context = document;
    selector = document.getElementsByTagName( selector );
    return jQuery.merge( this, selector );

    //處理: $(選擇器, $(...))
    } else if ( !context || context.jquery ) {
    return (context || rootjQuery).find( selector );

    // 處理: $(選擇器, 上下文)
    // (相當(dāng)于: $(上下文).find(選擇器)
    } else {
    return this.constructor( context ).find( selector );
    }


    3.4 jQuery.fn.extend (代碼 324 - 386 行)

    這個(gè)函數(shù)用于 擴(kuò)展函數(shù)

    函數(shù)中含多個(gè)參數(shù)判斷,為了使用可以更靈活。

    基本原理就是for(in),這里不具體介紹了。

    3.5 jQuery.noConflict (代碼 389 - 399 行 )
    noConflict: function( deep ) {
    window.$ = _$;

    if ( deep ) {
    window.jQuery = _jQuery;
    }

    return jQuery;
    },


    不多解釋了,就是讓 jQuery 恢復(fù)為全局的對(duì)象。

    3.6 jQuery.ready (代碼 407 -381 行)

    其中有2個(gè)函數(shù):

    jQuery.ready 觸發(fā)執(zhí)行 readyList 中的所有函數(shù)

    jQuery.bindReady 初始化讓 jQuery.ready 成功執(zhí)行

    bindReady: function() {

    // 如果已經(jīng)執(zhí)行 bindReady 則返回。
    if ( readyBound ) {
    return;
    }

    readyBound = true;

    // 如果頁面已經(jīng)加載, 馬上執(zhí)行 jQuery.ready
    if ( document.readyState === "complete" ) {
    return setTimeout( jQuery.ready, 1 );
    }

    // 標(biāo)準(zhǔn)瀏覽器支持 DOMContentLoaded
    if ( document.addEventListener ) {
    // 你懂的
    document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

    // 為什么還要 load ? , 因?yàn)橛行r(shí)候 DOMContentLoaded 失敗(如 iframe) ,而 load 總是會(huì)成功, 所以,同時(shí)處理 DOMContentLoaded load, 在 jQuery.ready 中會(huì)刪除監(jiān)聽函數(shù),保證最后這個(gè)函數(shù)只執(zhí)行一次
    window.addEventListener( "load", jQuery.ready, false );

    // IE瀏覽器( IE 8 以下)
    } else if ( document.attachEvent ) {

    // 使用 onreadystatechange
    document.attachEvent("onreadystatechange", DOMContentLoaded);

    // 同理
    window.attachEvent( "onload", jQuery.ready );

    // 如果 IE 下且非 iframe, 這里有個(gè)技巧。 見 doScrollCheck();
    // 原理: 瀏覽器在沒加載時(shí) 設(shè)置 scrollLeft 會(huì)錯(cuò)誤,所喲每隔1秒廁所 是否 scrollLeft 成功,如果發(fā)現(xiàn)成功,則執(zhí)行 jQuery.ready 。但這只對(duì)非 frame 會(huì)有用。
    var toplevel = false;

    try {
    toplevel = window.frameElement == null;
    } catch(e) {}

    if ( document.documentElement.doScroll && toplevel ) {
    doScrollCheck();
    }
    }
    },


    bindReady 函數(shù)在執(zhí)行 ready 時(shí)執(zhí)行。(jQuery 1.4 之前版本都是 絕對(duì)執(zhí)行,不管需不需要 ready 函數(shù))

    4. 生成 jQuery.support (代碼 1083 - 1276 行)

    人人都說 jQuery.support 是個(gè)好東西。確實(shí),這東西可以解決很多兼容問題。

    jQuery.support 是基于檢測(cè)的瀏覽器兼容方式。也就是說,創(chuàng)建一個(gè)元素, 看這個(gè)元素是否符合一些要求。

    比如測(cè)試元素是否支持checkOn屬性,只要先 set check = 'on' 然后看瀏覽器是否 get check == 'on'。

    此部分源碼不具體介紹了。

    5.和 data 有關(guān)擴(kuò)展 (代碼 1279 - 1510 行)

    jQuery的 data() 用于存儲(chǔ)一個(gè)字典。而這些數(shù)據(jù)最后都保存在 jQuery.cache ( 代碼 1283 行) , 全局對(duì)象存在 windowData ( 代碼 1279 行) 。

    但如果正確根據(jù)對(duì)象找到其在 jQuery.cache 的存儲(chǔ)對(duì)象? 這就是 expando 字符串。

    比如一個(gè)對(duì)象: elem 。

    滿足: elem.expando = "jQuery12321";

    那么 jQuery.cache["jQuery12321"] 就是存儲(chǔ)這個(gè) elem 數(shù)據(jù)的對(duì)象。

    實(shí)際上, 不是 elem.expando 表示鍵值,而是 elem[ jQuery.expando ] 表示。

    而一個(gè)對(duì)象數(shù)據(jù)又是一個(gè)字典,所以最后執(zhí)行 jQuery.data(elem, 'events') 后就是:

    jQuery.cache[elem[jQuery.expando]]['events'] 的內(nèi)容 (jQuery.cache[elem[jQuery.expando]] = {} )

    6.和隊(duì)列有關(guān)擴(kuò)展 (代碼 1514 - 1605 行)

    隊(duì)列是 jQuery 1.5 新增的。

    主要用于特效等需要等待執(zhí)行的時(shí)候。

    隊(duì)列主要操作就是 進(jìn)隊(duì)queue 出隊(duì)dequeue

    jQuery 隊(duì)列內(nèi)的數(shù)據(jù):

    如果沒有執(zhí)行:

    [將執(zhí)行的1, 將執(zhí)行的2]

    現(xiàn)在開始執(zhí)行 <將執(zhí)行的1>, 如果 type 為空或 "fx", 隊(duì)列內(nèi)數(shù)據(jù):

    ["inprogress", 將執(zhí)行的2]

    執(zhí)行完之后:

    ["將執(zhí)行的2]

    以上的這些數(shù)據(jù)都存在 jQuery.data(obj, (type || "fx") + "queue") (代碼 1520 - 1522行)

    jQuery.delay 則用于延時(shí)執(zhí)行一個(gè)函數(shù)。相當(dāng)于把原來隊(duì)列更新為 setTImeout 后的結(jié)果。 (代碼 1589 -1598 行)

    7.和屬性有關(guān)擴(kuò)展 (代碼 1609 - 1988 行)

    從這里開始,需要了解一個(gè)函數(shù)jQuery.access。對(duì)于 attr ,css 之類的函數(shù),如果需要返回值,只返回第一個(gè)元素的值,如果是設(shè)置值,則設(shè)置每個(gè)元素的值。這個(gè)神奇的效果就是 jQuery.access 搞定的。

    jQuery.access代碼在 794 - 819 行

    jQuery大部分函數(shù)都是依賴 jQuery.access 實(shí)現(xiàn)的,比如有一個(gè)函數(shù) XX,對(duì)用戶而言,調(diào)用的是 jQuery.fn.XX, 而這個(gè)函數(shù)需要對(duì)多個(gè)元素(jQuery數(shù)組內(nèi)的所有的節(jié)點(diǎn)) 操作,或者對(duì)1個(gè)元素操作, 通過 jQuery.access 轉(zhuǎn)換(不一定都是),最后只寫對(duì)1個(gè)元素的操作。這1個(gè)元素的操作往往是 jQuery.XX 函數(shù),因此,我們往往能看到即存在 jQuery.XX, 又存在 jQuery.fn.XX, 而其實(shí) jQuery.fn.XX 都是依靠 jQuery.XX 的,或者說jQuery.XX是底層函數(shù), jQuery.fn.XX 是方便用戶的工具 。

    jQuery.fn.attr 這個(gè)函數(shù)(代碼 1632 - 1634 行) 只有1句話,真正的實(shí)現(xiàn)是 jQuery.attr (代碼 1880 - 1988)

    又是一個(gè)大于100行的函數(shù)

    attr: function( elem, name, value, pass ) {
    // 檢查是否為 nodeType 為 Element
    if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) {
    return undefined;
    }

    // 如果這個(gè)屬性需要特殊對(duì)待。 height/width/left 等屬性需特殊計(jì)算
    if ( pass && name in jQuery.attrFn ) {
    return jQuery(elem)[name](value);
    }

    // 檢查是否為 XML 還 HTML
    var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
    // Whether we are setting (or getting)
    set = value !== undefined;

    // 修正名字, 比如 float 改 cssFloat
    name = notxml && jQuery.props[ name ] || name;

    // 只有在節(jié)點(diǎn)的時(shí)候執(zhí)行。
    if ( elem.nodeType === 1 ) {
    // 在 IE7- 下, href src 屬性直接獲取會(huì)返回絕對(duì)位置,而不是真實(shí)的位置字符串,
    // 要獲得它們的真實(shí)值,需要 elem.getAttribute("href", 2);
    var special = rspecialurl.test( name );

    // Safari 誤報(bào)默認(rèn)選項(xiàng)。通過獲取父元素的已選擇索引來修復(fù)。
    if ( name === "selected" && !jQuery.support.optSelected ) {
    var parent = elem.parentNode;
    if ( parent ) {
    parent.selectedIndex;

    // 對(duì) optgroups ,同理
    if ( parent.parentNode ) {
    parent.parentNode.selectedIndex;
    }
    }
    }

    // 檢查屬性是否存在, 有些時(shí)候 name in elem 會(huì)失敗,所以多次測(cè)試。
    if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) {

    // 如果設(shè)置屬性
    if ( set ) {
    // 在IE, 不能設(shè)置屬性 type 。
    if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
    jQuery.error( "type property can't be changed" );
    }

    // 如果 value === null, 表示移除屬性
    if ( value === null ) {
    if ( elem.nodeType === 1 ) {
    elem.removeAttribute( name );
    }

    } else {

    // 一切屬性設(shè)置就是1句話。。
    elem[ name ] = value;
    }
    }

    // 表單索引元素獲取需要 getAttributeNode( name ).nodeValue
    if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
    return elem.getAttributeNode( name ).nodeValue;
    }

    // elem.tabIndex 特殊處理
    if ( name === "tabIndex" ) {
    var attributeNode = elem.getAttributeNode( "tabIndex" );

    return attributeNode && attributeNode.specified ?
    attributeNode.value :
    rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
    0 :
    undefined;
    }

    return elem[ name ];
    }

    // 處理 style 屬性
    if ( !jQuery.support.style && notxml && name === "style" ) {
    if ( set ) {
    elem.style.cssText = "" + value;
    }

    return elem.style.cssText;
    }

    if ( set ) {
    // 這里除了 IE, 其它屬性使用標(biāo)準(zhǔn) setAttribute
    elem.setAttribute( name, "" + value );
    }

    // 如果屬性不存在,返回 undefined, 而不是 null 或 "" 之類的。
    if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) {
    return undefined;
    }

    // 見上
    var attr = !jQuery.support.hrefNormalized && notxml && special ?
    // Some attributes require a special call on IE
    elem.getAttribute( name, 2 ) :
    elem.getAttribute( name );

    // 同上
    return attr === null ? undefined : attr;
    }
    // 如果不是 DOM 元素,檢查處理。
    if ( set ) {
    elem[ name ] = value;
    }
    return elem[ name ];
    }


    windowData

    8.和事件有關(guān)擴(kuò)展 (代碼 1993 - 3175 行)

    8.1 事件

    平時(shí)我們都是調(diào)用 click(func) 之類的函數(shù), 而其實(shí)這些都是工具函數(shù),真正和事件掛鉤的函數(shù)是

    jQuery.fn.bind - 調(diào)用 jQuery.event.add

    jQuery.fn.unbind - 調(diào)用 jQuery.event.remove

    jQuery.fn.trigger - 調(diào)用 jQuery.event.trigger

    jQuery.fn.one - 調(diào)用 jQuery.fn.bind,Query.fn.unbind

    要想知道jQuery的事件原理,必須讀 jQuery.event.add (代碼 2012 - 2155 行)

    add: function( elem, types, handler, data ) {

    // 只對(duì)節(jié)點(diǎn)操作。
    if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
    return;
    }

    // IE 無法傳遞 window,而是復(fù)制這個(gè)對(duì)象 。
    if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
    elem = window;
    }

    // 如果 handler === false, 也就是說就是阻止某事件,
    // 這樣只要 bind("evt", false); 就是阻止此事件。
    if ( handler === false ) {
    handler = returnFalse;
    } else if ( !handler ) {
    return;
    }

    // handleObjIn 是內(nèi)部處理句柄, handleObj 是直接使用的處理句柄。
    var handleObjIn, handleObj;

    if ( handler.handler ) {
    handleObjIn = handler;
    handler = handleObjIn.handler;
    }

    // 為函數(shù)生成唯一的 guid 。具體下面介紹。
    if ( !handler.guid ) {
    handler.guid = jQuery.guid++;
    }

    // 獲取一個(gè)節(jié)點(diǎn)的數(shù)據(jù)。
    var elemData = jQuery.data( elem );

    // 如果沒有數(shù)據(jù),則直接返回。
    if ( !elemData ) {
    return;
    }

    // 避免和原生的js對(duì)象混淆。
    var eventKey = elem.nodeType ? "events" : "__events__",

    // 這里就是關(guān)鍵。
    // elemData 是存儲(chǔ)數(shù)據(jù)的位置, 而 elemData[ eventKey ] 就是存儲(chǔ)當(dāng)前事件的對(duì)象。 elemData.handle 就是當(dāng)前綁定的所有函數(shù)數(shù)組。
    // 也就是說,當(dāng)我們綁定一個(gè)函數(shù)時(shí),會(huì)往 elemData.handle 放這個(gè)函數(shù),然后事件觸發(fā)時(shí),會(huì)遍歷 elemData.handle 中函數(shù)然后去執(zhí)行。
    // 肯能有人會(huì)問,為什么這么做,因?yàn)樵腄OM內(nèi)部也有一個(gè) 函數(shù)數(shù)組,事件觸發(fā)后會(huì)執(zhí)行全部函數(shù)。答案還是 兼容。
    // 標(biāo)準(zhǔn)瀏覽器使用 addEventListener
    // IE 使用 attachEvent
    // 而這2者還是有差距的。因?yàn)?addEventListener 執(zhí)行函數(shù)的順序即添加函數(shù)的順序,然而 attachEvent 執(zhí)行函數(shù)的順序和添加的順序是相反的。
    // jQuery 使用自定義的 handler 數(shù)組,好處有:
    // 因?yàn)樽詈髢H綁定一次原生事件,事件觸發(fā)后,手動(dòng)執(zhí)行 數(shù)組中的函數(shù)。這樣保證兼容。
    // 同時(shí)也可以知道到底綁定了什么函數(shù),可以方便 trigger 函數(shù)的完成。

    events = elemData[ eventKey ],
    eventHandle = elemData.handle;

    // 一些功能。
    if ( typeof events === "function" ) {
    eventHandle = events.handle;
    events = events.events;

    } else if ( !events ) {
    if ( !elem.nodeType ) {
    elemData[ eventKey ] = elemData = function(){};
    }

    elemData.events = events = {};
    }

    // 如果是第一次執(zhí)行,需創(chuàng)建 eventHandle
    if ( !eventHandle ) {

    // eventHandle 就是真正綁定到原生事件的那個(gè)函數(shù),這個(gè)函數(shù)用來執(zhí)行events.hadlers 用。
    elemData.handle = eventHandle = function() {
    // Handle the second event of a trigger and when
    // an event is called after a page has unloaded
    return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
    jQuery.event.handle.apply( eventHandle.elem, arguments ) :
    undefined;
    };
    }

    // 綁定函數(shù)和原生,這樣可以保證函數(shù)可執(zhí)行為目前作用域。
    eventHandle.elem = elem;

    // 處理 jQuery(...).bind("mouseover mouseout", fn);
    types = types.split(" ");

    var type, i = 0, namespaces;

    while ( (type = types[ i++ ]) ) {
    handleObj = handleObjIn ?
    jQuery.extend({}, handleObjIn) :
    { handler: handler, data: data };

    // 略

    // 綁定 type guid
    handleObj.type = type;
    if ( !handleObj.guid ) {
    handleObj.guid = handler.guid;
    }

    // 獲取當(dāng)前的函數(shù)數(shù)組。
    var handlers = events[ type ],
    special = jQuery.event.special[ type ] || {};

    // 如果第一次,則創(chuàng)建這個(gè)數(shù)組。
    if ( !handlers ) {
    handlers = events[ type ] = [];

    // 特殊事件要執(zhí)行 setup 而不是標(biāo)準(zhǔn) addEventListener。
    // 此行用來支持自定義的事件。
    if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
    // 標(biāo)準(zhǔn)事件。 這里綁定的為 eventHandle
    if ( elem.addEventListener ) {
    elem.addEventListener( type, eventHandle, false );

    } else if ( elem.attachEvent ) {
    elem.attachEvent( "on"

    聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    jQuery1.5源碼解讀面向中高階JSER_jquery

    jQuery1.5源碼解讀面向中高階JSER_jquery:幾乎很難從jQuery分離其中的一部分功能。所以在這里我分享下應(yīng)該讀 jQuery 源碼的一些成果,以及讀源碼的方法??写a是必須的。 1. 代碼折疊是必須的。 因此必須在支持語法折疊的編輯器里打開源碼。 根據(jù)折疊層次,我們可以很快知道: 所有 jQuery 的
    推薦度:
    標(biāo)簽: 解讀 jQuery jquery源碼
    • 熱門焦點(diǎn)

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top