不廢話,直接上關鍵。這個系列中有好些直接借用別人的資料,我將他們整合在自認為比較合理的地方。所以在此先謝謝那些前輩。
注意:后續系列中jQuery實例多用$(...)來表示
1. 初始化與鏈式調用基礎
jQuery之所以能夠鏈式調用在於每次調用返回來jQuery本身。實現關鍵代碼如下。
jQuery = function(selector,context){ return new jQuery.fn.init(selector,context,rootjQuery); } ... rootjQuery = jQuery(document); ... jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function(selector,context,rootjQuery){
... return this; ... } } ... jQuery.fn.init.prototype = jQuery.fn; ... window.jQuery = window.$ = jQuery;
需要有幾個理解
a. new的深度理解
var obj = new Base();
這樣代碼的結果是什么,我們在Javascript引擎中看到的對象模型是:
new操作符具體干了什么呢?其實很簡單,就干了三件事情。
var obj = {}; obj.__proto__ = Base.prototype; Base.call(obj);
第一行,我們創建了一個空對象obj;
第二行,我們將這個空對象的__proto__成員指向了Base函數對象prototype成員對象;
第三行,我們將Base函數對象的this指針替換成obj,然后再調用Base函數,於是我們就給obj對象賦值了一個id(name,根據瀏覽器決定,chrome是name屬性)成員變量,這個成員變量的值是”Base”。
Base函數返回的結果會導致obj的結果不同。
舉例(chrome下):
function Base(){ this.name = “test”; this.a = “f”; return result; }
1) 根據new的原理,如果沒有返回值或返回值為數字或字符串或布爾類型,即result為null/number/string/bool,則new Base()返回的結果是本身,為
Base {name: "test", a: "f"}
2) 如果返回值為對象(數組或普通對象)或函數,則返回的對象或函數替換了Base本身;
拓展:
new Base() == Base () 返回的結果為false
例如當result為[]的時候,new Base()返回結果和Base()返回結果的都是[],但實際上他們並不相等 , Javascript 對於 Object 和 Function 的比較是基於引用的.
Var m = [],t = []; m == t;//false,並不是同一個引用
Var m = t = []; m == t;//true
b. jQuery中jQuery.fn為什么表現為數組
jQuery將對象模擬成了數組,而如何讓一個對象模擬成數組,jQuery給對象加上了以下幾個屬性:
{ length: 0, push: [].push, sort: [].sort, splice: [].splice },
不同的是chrome在給對象添加了length和splice后真的轉化成了數組,如$()結果是[],而ie沒有轉化$()結果是{}。但是無所謂,他們都可以使用length等屬性,不影響后續使用。如果$(…)有搜索結果,jQuery會把結果拼接成數組返回,這樣jQuery的返回結果看起來總是數組。
總結
由上面的分析可知jQuery.fn.init.prototype = jQuery.fn目的就是將jQuery.fn上的所有屬性都掛在jQuery實例$(...)上,使得實例擁有很多jQuery.fn上定義的函數。比如jQuery.fn.extend函數,實例就可以直接使用:$(...).extend({"name": "chua"})。
由於每次都是一個新的實例new jQuery.fn.init(selector,context,rootjQuery),所以各個實例是獨立的。而jQuery全局的屬性直接掛在jQuery上,比如jQuery.extend,這個和jQuery.fn.extend不一樣了,因為jQuery.extend是全局的,比如jQuery.extend({"test": "chua"})你可以隨時通過jQuery.test就把值給取出來了,而jQuery實例則需要保證同一個實例的情況下才能取到值。比如var ps = $("p").extend({"test": "chua"}),通過ps.test能夠取到值,但是你使用$("p").test是取不到的。因為你使用$(...)又新建了一個實例。
至於jQuery的鏈式調用很好理解,源碼初始化的時候返回了jQuery對象本身:
init: function(selector,context,rootjQuery){ ... return this; }
這一節先到這里,待續……