最近想看一下jquery源碼,搜到了這樣一篇博客《從jQuery源碼學到的10件事情》
本文基於這篇視頻博客,提煉了一些內容,分享給大家。
說明:
這篇文章寫於2010年,作者在影片裡使用的是jQuery 1.4版本,我根據影片裡講到的內容,對應目前的1字頭1.11版本做了一些調整,一些被拋棄或被移除的內容頁做了刪減,並在此感謝原作者
#黑箱/Black box
黑箱系統的概念是給定輸入返回輸出的一個系統,黑箱把實現過程進行封裝。這裡說的jQuery黑箱是為js全域變數window輸出jQuery 和 $,而過程被封裝到黑箱裡,與外界互不干擾。
jQuery 1.4版本的黑箱是利用了類似如下的自執行函數
(function( window, undefined){})(window)
作者給了一個比較通用的實現黑箱的方法
undefined = true; (function(window, document, undefined){ if(foo == undefined) { } })(this, document)
jQuery的黑箱裡多傳了第三個形參叫做undefined,而傳實參的時候並沒有傳值,js裡沒有傳值的形參會被設定為undefined,保證了黑箱內部undefined的正確性。在js中,undefined作為一個全域屬性,是可以被賦值的,例如上述程式碼中的undefined = true;
以自執行函數的模式實現黑箱的另一個好處是利於壓縮,例如下述的情況,我們只需要在黑箱內部使用簡單的變數。
(function(A, B, C)){ B.getElementById('') })(this, document)
作者為匿名函數自執行舉了很多例子,比如下面這個,為頁面的某一部分不停地更新(以及不斷地執行)
(function loop(){ doStuff(); $('#update').load('awesomething.php',function(){ loop(); }) //setTimeout(loop, 100) })()
jQuery 1.11版本的黑箱採用了全新的工廠方法,本文不探究
noConflict的實作
這個函數的差異不大,1.11 版本程式碼如下
var // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$; jQuery.noConflict = function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; };
我們可以看到防衝突的實作是先把之前的JQuery 和$ 存起來,noConflict被呼叫的時候,再還給它們
與原生js屬性命名的轉換
##1.4版本用的是props物件來存放jquery對屬性操作與原生js屬性操作的對應關係1.11版縮減版本是這樣的
jQuery.extend({ propFix: { "for": "htmlFor", "class": "className" }, prop: function( elem, name, value ) { //... name = jQuery.propFix[ name ] || name; }, propHooks: { //... } }); jQuery.each([ "tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable" ], function() { jQuery.propFix[ this.toLowerCase() ] = this; });propFix 這個物件是存放對應關係表的,例如class轉換成className,prop函數負責處理這個關係表。
而下面的each很有意思,
遍歷數組中那些屬性,然後把他們小寫格式對應到自己,放到 propFix
jQuery.fx.speeds = { slow: 600, fast: 200, // Default speed _default: 400 };調皮的原作者做了這樣一些事情:
var isIE //... jQuery.fx.speeds._default = isIE ? 800 : 400 jQuery.fx.speeds.veryfast = 200; $('...').fadeIn('veryfast')一種是可以對default屬性做.readyready函數1.11版本和1.4版本有較大的差距,新版中很多東西我也不太能理解,我們就簡單的把核心拿出來看一下
jQuery.ready.promise = function( obj ) { //...省略若干 } else if ( document.addEventListener ) { // 使用addEventListener "DOMContentLoaded" 监听ready事件 document.addEventListener( "DOMContentLoaded", completed, false ); // 备选方案 "load" window.addEventListener( "load", completed, false ); //如果IE } else { // Ensure firing before onload, maybe late but safe also for iframes //IE下 attachEvent 的"onreadystatechange" document.attachEvent( "onreadystatechange", completed ); // A fallback to window.onload, that will always work //备选方案onload window.attachEvent( "onload", completed ); // If IE and not a frame // continually check to see if the document is ready var top = false; try { top = window.frameElement == null && document.documentElement; } catch(e) {} if ( top && top.doScroll ) { (function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); // and execute any waiting functions jQuery.ready(); } })(); } } } return readyList.promise( obj );}; .ready 利用了下面的.promise去做确保载入完成的工作,重点是document.addEventListener( "DOMContentLoaded", completed, false );window.addEventListener( "load", completed, false );document.attachEvent( "onreadystatechange", completed );window.attachEvent( "onload", completed );相容性考慮的四種檢查方式
$('#id tag.thing') ------- using sizzle
jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); }jQuery物件其實是return了一個它自己的
// Initialize a jQuery object init = jQuery.fn.init = function( selector, context ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) //超级省略...下略 // Handle HTML strings // HANDLE: $(html) -> $(array) // HANDLE: $(html, props) // HANDLE: $(#id) // HANDLE: $(expr, $(...)) // HANDLE: $(expr, context) // HANDLE: $(DOMElement) // HANDLE: $(function) return jQuery.makeArray( selector, this ); }; // Give the init function the jQuery prototype for later instantiation init.prototype = jQuery.fn;從上面的摘取的在程式碼註解中,我們可以看到jq自己的構造函數裡處理了哪些情況,其中包括html標籤名和id的獲取,意味著這兩種獲取是最底層的,此外$()的其他處理都要經過其他的函數,效率上不如上述處理情形。
同時我們也能看到init的原型被賦予了jQuery.fn, 關於jQuery物件的相關內容,有興趣的朋友可以再多去了解一些。
Sizzle.selectors.pseudos裡面
以上是從jQuery應該明白哪些知識?的詳細內容。更多資訊請關注PHP中文網其他相關文章!