<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題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關鍵字專題關鍵字專題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
        當前位置: 首頁 - 科技 - 知識百科 - 正文

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

        來源:懂視網 責編:小采 時間:2020-11-27 20:58:45
        文檔

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

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

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

        1. 代碼折疊是必須的。

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

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

        })(window);

        這樣可以避免內部對象污染全局。傳入的參數1是 window, 參數2是 undefined , 加快js搜索此二對象的速度。

        2. 接著打開第一級折疊。

        可以發現 jQuery 代碼是按這樣順序來組織:

      1. 定義 jQuery 函數 ( 代碼 20 - 1081 行)
      2. 生成 jQuery.support (代碼 1083 - 1276 行)
      3. 和 data 有關擴展 (代碼 1279 - 1510 行)
      4. 和隊列有關擴展 (代碼 1514 - 1605 行)
      5. 和屬性有關擴展 (代碼 1609 - 1988 行)
      6. 和事件有關擴展 (代碼 1993 - 3175 行)
      7. 內部的Sizzle CSS Selector Engine (代碼 3183 - 4518 行)
      8. 和節點有關擴展 (代碼 4520 - 5492 行)
      9. 和樣式有關擴展 (代碼 5497 - 5825 行)
      10. 和ajax有關擴展 (代碼 5830 - 7172 行)
      11. 和效果有關擴展 (代碼 7176 - 7696 行)
      12. 和定位有關擴展 (代碼 7700 - 8065 行)
      13. 下面的模塊可以用上面的模塊,上面的模塊不需要下面的模塊

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

        總的代碼是這樣的框架:

        var jQuery = (function() {
        // 創建 jQuery 對象
        var jQuery = function( selector, context ) {
        // 略

        };

        // 創建 jQuery.fn 對象
        jQuery.fn = jQuery.prototype = {
        // 略
        };

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

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

        });

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

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

        })();

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

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

        jQuery對象似乎一直都是這東西:

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

        這個函數表示: 要想知道函數 jQuery 是什么東西,必須看 jQuery.fn.init 對象。

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

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

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

        這個fn 其實是 jQuery.prototype ,這也是為啥jQuery.fn 就是擴展 jQuery對象的唯一原因。

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

        jQuery 對js對象處理和中國人講話一樣繞。這里總結下到底 jQuery 對象是個什么家伙。

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

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

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

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

        constructor - 手動指定一個構造函數。 因為默認是 jQuery.fn.init

        length - 讓這個對象更接近一個 原生的數組

        size - 返回 length

        toArray - 通過 Array.prototype slice 實現生成數組

        get - 即 this[ num ] ,當然作了下 參數索引 的處理。

        pushStack - 加入一個元素

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

        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 就是所謂的 $ 函數。 也就是說,平常的 $("#id") 就是 new jQuery.fn.init("#id");

        這個函數很長,但代碼覆蓋率小。

         init: function( selector, context, rootjQuery ) {
        // 參數: selector 選擇器
        // context 上下文
        // rootjQuery 父節點

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

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

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

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

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

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

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

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

        // 略。

        // 如果傳入的是一個 Dom列表 ( getElementsByTagName 結果 ) 則轉為 jQuery 數組。
        return jQuery.makeArray( selector, this );
        }

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

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

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

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

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

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

        // 返回 createElement("tag")

        return jQuery.merge( this, selector );

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

        // 因為有的瀏覽器 getElementById 不只返回 id匹配的,所以做檢查。
        return this;
        }

        // 處理 $("標簽")
        } 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 );

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


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

        這個函數用于 擴展函數

        函數中含多個參數判斷,為了使用可以更靈活。

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

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

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

        return jQuery;
        },


        不多解釋了,就是讓 jQuery 恢復為全局的對象。

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

        其中有2個函數:

        jQuery.ready 觸發執行 readyList 中的所有函數

        jQuery.bindReady 初始化讓 jQuery.ready 成功執行

        bindReady: function() {

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

        readyBound = true;

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

        // 標準瀏覽器支持 DOMContentLoaded
        if ( document.addEventListener ) {
        // 你懂的
        document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

        // 為什么還要 load ? , 因為有些時候 DOMContentLoaded 失敗(如 iframe) ,而 load 總是會成功, 所以,同時處理 DOMContentLoaded load, 在 jQuery.ready 中會刪除監聽函數,保證最后這個函數只執行一次
        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, 這里有個技巧。 見 doScrollCheck();
        // 原理: 瀏覽器在沒加載時 設置 scrollLeft 會錯誤,所喲每隔1秒廁所 是否 scrollLeft 成功,如果發現成功,則執行 jQuery.ready 。但這只對非 frame 會有用。
        var toplevel = false;

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

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


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

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

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

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

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

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

        5.和 data 有關擴展 (代碼 1279 - 1510 行)

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

        但如果正確根據對象找到其在 jQuery.cache 的存儲對象? 這就是 expando 字符串。

        比如一個對象: elem 。

        滿足: elem.expando = "jQuery12321";

        那么 jQuery.cache["jQuery12321"] 就是存儲這個 elem 數據的對象。

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

        而一個對象數據又是一個字典,所以最后執行 jQuery.data(elem, 'events') 后就是:

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

        6.和隊列有關擴展 (代碼 1514 - 1605 行)

        隊列是 jQuery 1.5 新增的。

        主要用于特效等需要等待執行的時候。

        隊列主要操作就是 進隊queue 出隊dequeue

        jQuery 隊列內的數據:

        如果沒有執行:

        [將執行的1, 將執行的2]

        現在開始執行 <將執行的1>, 如果 type 為空或 "fx", 隊列內數據:

        ["inprogress", 將執行的2]

        執行完之后:

        ["將執行的2]

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

        jQuery.delay 則用于延時執行一個函數。相當于把原來隊列更新為 setTImeout 后的結果。 (代碼 1589 -1598 行)

        7.和屬性有關擴展 (代碼 1609 - 1988 行)

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

        jQuery.access代碼在 794 - 819 行

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

        jQuery.fn.attr 這個函數(代碼 1632 - 1634 行) 只有1句話,真正的實現是 jQuery.attr (代碼 1880 - 1988)

        又是一個大于100行的函數

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

        // 如果這個屬性需要特殊對待。 height/width/left 等屬性需特殊計算
        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;

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

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

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

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

        // 如果設置屬性
        if ( set ) {
        // 在IE, 不能設置屬性 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 {

        // 一切屬性設置就是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, 其它屬性使用標準 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.和事件有關擴展 (代碼 1993 - 3175 行)

        8.1 事件

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

        jQuery.fn.bind - 調用 jQuery.event.add

        jQuery.fn.unbind - 調用 jQuery.event.remove

        jQuery.fn.trigger - 調用 jQuery.event.trigger

        jQuery.fn.one - 調用 jQuery.fn.bind,Query.fn.unbind

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

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

        // 只對節點操作。
        if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
        return;
        }

        // IE 無法傳遞 window,而是復制這個對象 。
        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 是內部處理句柄, handleObj 是直接使用的處理句柄。
        var handleObjIn, handleObj;

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

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

        // 獲取一個節點的數據。
        var elemData = jQuery.data( elem );

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

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

        // 這里就是關鍵。
        // elemData 是存儲數據的位置, 而 elemData[ eventKey ] 就是存儲當前事件的對象。 elemData.handle 就是當前綁定的所有函數數組。
        // 也就是說,當我們綁定一個函數時,會往 elemData.handle 放這個函數,然后事件觸發時,會遍歷 elemData.handle 中函數然后去執行。
        // 肯能有人會問,為什么這么做,因為原生的DOM內部也有一個 函數數組,事件觸發后會執行全部函數。答案還是 兼容。
        // 標準瀏覽器使用 addEventListener
        // IE 使用 attachEvent
        // 而這2者還是有差距的。因為 addEventListener 執行函數的順序即添加函數的順序,然而 attachEvent 執行函數的順序和添加的順序是相反的。
        // jQuery 使用自定義的 handler 數組,好處有:
        // 因為最后僅綁定一次原生事件,事件觸發后,手動執行 數組中的函數。這樣保證兼容。
        // 同時也可以知道到底綁定了什么函數,可以方便 trigger 函數的完成。

        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 = {};
        }

        // 如果是第一次執行,需創建 eventHandle
        if ( !eventHandle ) {

        // eventHandle 就是真正綁定到原生事件的那個函數,這個函數用來執行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;
        };
        }

        // 綁定函數和原生,這樣可以保證函數可執行為目前作用域。
        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;
        }

        // 獲取當前的函數數組。
        var handlers = events[ type ],
        special = jQuery.event.special[ type ] || {};

        // 如果第一次,則創建這個數組。
        if ( !handlers ) {
        handlers = events[ type ] = [];

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

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

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

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

        jQuery1.5源碼解讀面向中高階JSER_jquery:幾乎很難從jQuery分離其中的一部分功能。所以在這里我分享下應該讀 jQuery 源碼的一些成果,以及讀源碼的方法。啃代碼是必須的。 1. 代碼折疊是必須的。 因此必須在支持語法折疊的編輯器里打開源碼。 根據折疊層次,我們可以很快知道: 所有 jQuery 的
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 丝袜熟女国偷自产中文字幕亚洲| 毛片免费视频播放| 亚洲免费无码在线| 韩国亚洲伊人久久综合影院| 精品少妇人妻AV免费久久洗澡| 亚洲人成色777777老人头| 成人免费看片又大又黄| 亚洲AV无码一区二区三区牲色| 国产成人精品免费视频软件| 国产成人亚洲精品蜜芽影院| 免费大香伊蕉在人线国产 | 亚洲色婷婷六月亚洲婷婷6月| 亚洲第一精品福利| 日本xxxx色视频在线观看免费| 亚洲av无码专区在线播放| 亚洲一级免费毛片| 亚洲s码欧洲m码吹潮| 欧洲精品99毛片免费高清观看| 久久av无码专区亚洲av桃花岛| 91黑丝国产线观看免费| 亚洲日韩精品无码专区加勒比 | 免费大黄网站在线看| 久久WWW免费人成—看片| 亚洲a一级免费视频| 成人激情免费视频| 深夜福利在线视频免费| 国产国拍亚洲精品mv在线观看 | 亚洲国产综合91精品麻豆| 五月婷婷综合免费| 日韩精品无码免费视频| 久久99国产亚洲精品观看| 成人免费无码大片A毛片抽搐| 精品国产污污免费网站入口| 亚洲国产精品成人综合色在线婷婷 | 亚洲人成网站18禁止久久影院| 国产在线播放免费| 人妻无码一区二区三区免费| 美女羞羞视频免费网站| 又爽又黄无遮挡高清免费视频| 手机看片国产免费永久| 亚洲丰满熟女一区二区哦|