先看看他的框架吧,了解了jquery的最小系統最小框架,大家等下就發現,他其實什么都沒有做,這個就只是一個初始的骨架而已,當然,了解一下,對於我們應用他,還有擴展他應該是有所助益的.
另,本人js純菜鳥一枚,生怕誤導了和我一樣的菜鳥階級朋友,所以請大家在看的同時多動手,呵呵,也希望路過的大牛們順手指正.非常感謝.
最小框架
(function(window, undefined) { var rootjQuery, core_version = "1.9.1", _jQuery = window.jQuery, _$ = window.$, jQuery = function(selector, context) { return new jQuery.fn.init(selector, context, rootjQuery); }; jQuery.fn = jQuery.prototype = { jquery: core_version, constructor: jQuery, init: function(selector, context, rootjQuery) { return this; } }; jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function(dest, src) { for (var p in src) { dest[p] = src[p]; } return dest; } jQuery.extend(jQuery, { noConflict: function(deep) { if (window.$ === jQuery) { window.$ = _$; } if (deep && window.jQuery === jQuery) { window.jQuery = _jQuery; } return jQuery; } }); jQuery.extend(jQuery.fn, { method1: function(msg) { alert(msg); return this; } ,method2: function(msg) { alert(msg); return this; } }); window.jQuery = window.$ = jQuery; })(window);
jQuery.extend這個方法被我簡寫了,僅僅為了最小系統少幾行代碼,顯得稍微清晰點而已.
調用示例
$().method1("Hello").method2("World!");
鏈式調用風格,很方便的.
如何擴展它?
(function(jQuery, undefined) { jQuery.fn.extend(jQuery.fn, { method3: function(msg) { alert("method2:" + msg); return this; } }); })(jQuery)
經過這么擴展,我們就有method3這個新的方法了,和method1等方法的調用什么都是一樣的.
他是如何工作的?
首先,所有的工作都是在一個函數里面完成的(不包括擴展的部分),這是一個自運行函數,如果您對什么是自運行函數不太了解,可以參考一下函數聲明,函數表達式等的資料.
先附上帶代碼注釋吧,錯漏的地方肯定不少,請大家批評指正.
/*! * jQuery 最小系統 * Date: 2013-04-25 */ //一個自運行的函數. (function(window, undefined) { var //到jQuery(document)的一個引用,所有的jquery對象都將引用到他 rootjQuery, //定義自己的版本號 core_version = "1.9.1", //通過局部變量保存可能會被覆蓋的window屬性 //如果用戶調用jQuery.noConflict(deep)方法 //則會恢復window.jQuery和window.$的值 //目的是為了和別人和平共處互不沖突 _jQuery = window.jQuery, _$ = window.$, //我個人的理解是按jQuery().m1().m2()這種調用方式導致這么處理? //這意味着jQuery()返回的對象與m1,m2應該有相同的prototype?this? //從而,假設返回的是new init() //那么init.prototype===jQuery.prototype //那么... jQuery = function(selector, context) { //注釋掉的這個有什么區別,有什么不妥嗎? //如果使用了new的話,那么init函數中即使不return this應該也是可以的. //可見,new是在背后做了一些額外工作的 //詳情在本文的后面有說明 //不過,剛查看到有人說了,這里用new,還有個隔離作用域的作用,表示不怎么明白,回去思考去,呵呵 //關於這個隔離作用域,在文章后面有說明. //很多不該有的注釋保留,是因為這個記錄了本人的思考過程,嗯,由完全不明白,到明白一些些了,呵呵 //return jQuery.fn.init(selector, context, rootjQuery); return new jQuery.fn.init(selector, context, rootjQuery); }; jQuery.fn = jQuery.prototype = { jquery: core_version, constructor: jQuery,//注釋掉的話,有什么后果?在本例中倒是沒什么 init: function(selector, context, rootjQuery) { return this; } }; //要讓jquery()能復用jquery.fn的屬性? jQuery.fn.init.prototype = jQuery.fn; //擴展對象,這個已經簡化了,所以他的調用方式也就面目全非了 jQuery.extend = jQuery.fn.extend = function(dest, src) { for (var p in src) { dest[p] = src[p]; } return dest; } jQuery.extend(jQuery, { //避免沖突 noConflict: function(deep) { if (window.$ === jQuery) { window.$ = _$; } if (deep && window.jQuery === jQuery) { window.jQuery = _jQuery; } return jQuery; } }); jQuery.extend(jQuery.fn, { //定義自己的方法,沒啥用 method1: function(msg) { alert("method1:" + msg); //都記得要返回,從而實現鏈式調用 return this; } , method2: function(msg) { alert("method2:" + msg); return this; } }); //最頂級的jquery對象,所有其他jquery都將引用到他 rootjQuery = jQuery(document); //不管這兩屬性是否會沖突,用了再說 //等用戶自己調用noConflict吧,如果沖突的話 window.jQuery = window.$ = jQuery; })(window);
補充一點,本人一直迷糊的地方,就是,看看一個對象是如何new出來的?
最好當然是看ECMA文檔了,下面的這個請在FF,Chrome下測試哦,IE就自動忽略吧.
var JSEngine = function(fn) { var This = this; this.constructor = fn; //偽代碼 this.newObject = function() { var o = {}//創建一個原生對象 , _constructor = This.constructor; //查看構造函數的prototype類型是否為object //是則將對象的內部屬性Prototype應用到它 //否則此屬性指向Object.prototype if (typeof _constructor.prototype === "object") { o.__proto__ = _constructor.prototype; } else { o.__proto__ = Object.prototype; //{}? } //調用構造函數 var o2 = _constructor.apply(o, arguments); //如果返回的是對象,則返回這個o2,否則返回o if (typeof o2 === "object") { return o2; } else { return o; } } }
從上面的代碼可以看出,當使用new構建一個對象的時候,總是會返回一個object,這也是為什么前面使用:
return
new
jQuery.fn.init(selector, context, rootjQuery);
而不是return
jQuery.fn.init(selector, context, rootjQuery);
的原因(我個人猜想的啊,主要是我沒有看出有別的不妥的地方,請過路的大牛指點啊!!!后來才明白,其實應該是后面說道的隔離作用域的原因啊)
補充,剛從有些資料上看到,說此處用new是為了隔離作用域,哎,還得學習啊!!!
測試代碼如下:
function fn1() { this.name = "AAA"; } var js = new JSEngine(fn1); var o1 = js.newObject(); var o2 = new fn1(); alert(o1.name); //AAA alert(o2.name); //AAA alert(o1 instanceof fn1); //true alert(o2 instanceof fn1); //true
那么,正常的函數調用會是什么樣子呢?正常的函數調用的話看看下面的偽代碼:
function callFunction(fn, caller) { caller = caller || window; fn.apply(caller); }
這里的caller與arguments.callee.caller是兩碼事.
由上面的偽代碼看出,fn函數體內部的this,指向的就是caller. 那么,這個caller是什么?就是函數的調用者,常見有如下形式:
fn();//caller 默認就是全局對象 x.y.fn();//caller就是x.y
其實一般的場景都是這么簡單的.那么,我們應該能夠理解內部構造函數jQuery內部為什么是:
return new jQuery.fn.init(selector, context, rootjQuery);
而非
return jQuery.fn.init(selector, context, rootjQuery);
了吧? 前者得到的都是一個全新的對象(那么,作用域隔離的目的).后者的話,在init內部return this的話,總是得到同一個對象,那就是jQuery.fn, 這個意味着$()在任何地方都得到了一個唯一的相同的對象,這個就不能實現我們的目標了.
強烈推薦大家看《深入理解JavaScript系列》
最后,感謝John大神!!!