先看看他的框架吧,了解了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大神!!!
