core是jQuery的核心內容, 包含了最基礎的方法, 比如我們常用的 $(selector, context), 用於遍歷操作的 each, map, eq, first 識別變量類型的 isArray, isNumeric, type 等 . 這些方法為jQuery后續操作提供最基礎的支持.
構造函數 jQuery( selector, context )
說到jQuery, 大家可能最熟悉的就是 $(selector, context) , 我覺得這也是jQuery受到人們歡迎的很大一部分原因, 因為這個方法非常的強大.
// Define a local copy of jQuery 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 ); },
這里我們很明顯的看到一個關鍵詞就是new ,這說明每一次調用$()就會new一個jQuery對象出來 , 有些人可能不注意這一點就會寫出下面的代碼, 或者會出現 $("#id") === $("#id")的這種判斷 , 這種寫法都是不可取的, 我們應該盡量的節省jQuery的獲取次數, 重復利用jQuery對象.
if($(".class").hasClass()){ $(".class").removeClass(); }
靜態屬性和原型屬性
從core.js中可以看到兩類屬性( q君: 函數也是屬性哦! ), 一類是以jQuery.extend({})定義的靜態屬性, 一類是通過 jQuery.fn = jQuery.prototype = {} 進行定義的原型屬性. 靜態屬性是jQuery函數的屬性, 通過 $調用, 如$.each . 靜態屬性通常為與頁面元素無關的工具方法. 原型屬性是拓展jQuery對象的一些功能, 它持有jQuery對象自身(this) , 為處理自身對象之用 調用形式為 var $a = $("a"); $a.each() .( q君: jQuery里面有兩個each ,要分清 )
具體的實現方法都比較簡單, 就不再一一敘述. jQuery.extend 是一個很常用的方法, 它可以將幾個對象合並成一個對象, 並且支持深拷貝和淺拷貝兩種方式 , 在做一些默認配置和實現的時候會經常用到.
jQuery對象創建
通過查看 jQuery( selector, context )函數, 知道了 jQuery 調用了 new jQuery.fn.init( selector, context ). 在這句話上面有一條注釋: Need init if jQuery is called . 我們在 /src/core/目錄下找到init.js. 內容大致如下
init = jQuery.fn.init = function( selector, context ) { // ... // ... return this; // ... retrun this.constructor( context ).find( selector ); // ... return ( context || rootjQuery ).find( selector ); // ... return typeof rootjQuery.ready !== "undefined" ? rootjQuery.ready( selector ) : // Execute immediately if ready is not present selector( jQuery ); // ... return jQuery.makeArray( selector, this ); } // Give the init function the jQuery prototype for later instantiation init.prototype = jQuery.fn;
在這個方法里有很多種返回.
第一種 this, 返回的是init的對象;
第二種 jquery對象.find(); -> /src/traversing/findFilter.js : find -> return this.pushStack -> return jQuery.merge( this.constructor(), elems ); -> jQuery對象
第三種 selector(jQuery); 不一定返回jQuery對象
第四種 rootjQuery.ready( selector ); -> /src/core/ready.js : ready -> return this(rootjQuery) -> jQuery對象
第五種 jQuery.makeArray( selector, this ); -> var ret = results; return ret; -> jQuery對象
通過上述觀察, 發現jQuery方法只有一種情況下返回的不是jQuery對象: 傳入的selector參數為對象, 並且沒有加載 /src/core/ready.js 模塊. 下面這段代碼也會證明這種情況(代碼會在附件中, 請及時更新).
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>core</title> </head> <body> <script src="require.js" data-main="main" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" charset="utf-8"> require(['../src/core/init'], function(init) { var ret = new init(function() { return { name: "not jquery" }; }); console.log(ret); }) </script> </body> </html>
再來看第一種情況, return this返回的是init對象, 並不是jQuery對象, 但是我們在下面看到 init.prototype = jQuery.fn; 所以通過init創建的對象也就是jQuery對象.
jQuery實現偽數組
我們在用jQuery的過程中很多情況下會把jQuery當做數組去用. 但是我們從上面創建過程來看, jQuery貌似跟數組並沒有什么關系. 那么我們來分析一下他的原型看看為什么jQuery可以像數組一樣使用.
在這之前我先介紹一下"鴨子類型(duck typing)" ( q君: 鴨子? 好吃嗎? ), 什么是鴨子類型? “當看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子。” 這是一個非常恰當的描述, 在動態語言中我們不需要管一個對象到底是什么類型, 只要他能執行某個方法, 那么我就可以認為他就是某個類型的對象.
Javascript就是這樣的一種語言. 要實現數組不一定要繼承或者使用Array對象. 只要實現了Array對象里面的方法, 就可以認為他是數組. 這里我也發現一個很有趣的事情. 用chrome瀏覽器進行調試的時候, 我們用console.log輸出普通對象和數組的時候輸出的格式不一樣. 輸出對象類似於 " f {length: 0} " , 輸出數組類似於 " [1] ". 我們通過下面幾行代碼做個試驗
var f = function(){this.length = 1; this[0] = "a" } console.log(new f()); // f {0: "a", length: 1} var f = function(){this.length = 1;this.splice = function(){};this[0] = "a" } console.log(new f()); // ["a"]
哈, 多么神奇! chrome把他當成數組了! 如果一個對象中length為數字, splice為方法, 這個對象就會被chrome認為是數組. 大家感興趣的話可以試一下其他的瀏覽器.
嗯, 我們回過頭看jQuery的prototype, jQuery的prototype中包含了數組中常用的 length屬性, push , sort , splice , slice等方法.
所有jQuery就像一個數組一樣使用.
使用建議
1. 盡量減少重復使用 $()方法獲取相同的對象
2. $() 大部分會返回jQuery對象, 但不排除在極端情況
3. jQuery可以當做數組使用, 但不完全是數組, pop, shift 等方法不適用於jQuery對象.
附件
http://yunpan.cn/Q7nKEsZ9cqFby 提取碼 3a4a
