jQuery源碼分析-03構(gòu)造jQuery對(duì)象-源碼結(jié)構(gòu)和核心函數(shù)
更新時(shí)間:2011年11月14日 23:40:23 作者:
jQuery源碼分析-03構(gòu)造jQuery對(duì)象-源碼結(jié)構(gòu)和核心函數(shù),需要的朋友可以參考下。
作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com
畢竟是邊讀邊寫(xiě),不對(duì)的地方請(qǐng)告訴我,多多交流共同進(jìn)步。本章還未寫(xiě)完,完了會(huì)提交PDF。
前記:
想系統(tǒng)的好好寫(xiě)寫(xiě),但是會(huì)先從感興趣的部分開(kāi)始。
近期有讀者把PDF傳到了百度文庫(kù)上,首先感謝轉(zhuǎn)載和傳播,但是據(jù)為已有并設(shè)置了挺高的財(cái)富值才能下載就不好了,以后我整理好了會(huì)傳到文庫(kù)上。請(qǐng)?bào)w諒一下。
3. 構(gòu)造jQuery對(duì)象
3.1 源碼結(jié)構(gòu)
先看看總體結(jié)構(gòu),再做分解:
(function( window, undefined ) {
var jQuery = (function() {
// 構(gòu)建jQuery對(duì)象
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
// jQuery對(duì)象原型
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
// selector有以下7種分支情況:
// DOM元素
// body(優(yōu)化)
// 字符串:HTML標(biāo)簽、HTML字符串、#id、選擇器表達(dá)式
// 函數(shù)(作為ready回調(diào)函數(shù))
// 最后返回偽數(shù)組
}
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
// 合并內(nèi)容到第一個(gè)參數(shù)中,后續(xù)大部分功能都通過(guò)該函數(shù)擴(kuò)展
// 通過(guò)jQuery.fn.extend擴(kuò)展的函數(shù),大部分都會(huì)調(diào)用通過(guò)jQuery.extend擴(kuò)展的同名函數(shù)
jQuery.extend = jQuery.fn.extend = function() {};
// 在jQuery上擴(kuò)展靜態(tài)方法
jQuery.extend({
// ready bindReady
// isPlainObject isEmptyObject
// parseJSON parseXML
// globalEval
// each makeArray inArray merge grep map
// proxy
// access
// uaMatch
// sub
// browser
});
// 到這里,jQuery對(duì)象構(gòu)造完成,后邊的代碼都是對(duì)jQuery或jQuery對(duì)象的擴(kuò)展
return jQuery;
})();
window.jQuery = window.$ = jQuery;
})(window);
l jQuery對(duì)象不是通過(guò) new jQuery 創(chuàng)建的,而是通過(guò) new jQuery.fn.init 創(chuàng)建的
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
n jQuery對(duì)象就是jQuery.fn.init對(duì)象
n 如果執(zhí)行new jQeury(),生成的jQuery對(duì)象會(huì)被拋棄,最后返回 jQuery.fn.init對(duì)象;因此可以直接調(diào)用jQuery( selector, context ),沒(méi)有必要使用new關(guān)鍵字
l 先執(zhí)行 jQuery.fn = jQuery.prototype,再執(zhí)行 jQuery.fn.init.prototype = jQuery.fn,合并后的代碼如下:
jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
所有掛載到j(luò)Query.fn的方法,相當(dāng)于掛載到了jQuery.prototype,即掛載到了jQuery 函數(shù)上(一開(kāi)始的 jQuery = function( selector, context ) ),但是最后都相當(dāng)于掛載到了 jQuery.fn.init.prototype,即相當(dāng)于掛載到了一開(kāi)始的jQuery 函數(shù)返回的對(duì)象上,即掛載到了我們最終使用的jQuery對(duì)象上。
這個(gè)過(guò)程非常的繞,金玉其外“敗絮”其中??!
3.2 jQuery.fn.init
jQuery.fn.init的功能是對(duì)傳進(jìn)來(lái)的selector參數(shù)進(jìn)行分析,進(jìn)行各種不同的處理,然后生成jQuery對(duì)象。
類型(selector)
處理方式
DOM元素
包裝成jQuery對(duì)象,直接返回
body(優(yōu)化)
從document.body讀取
單獨(dú)的HTML標(biāo)簽
document.createElement
HTML字符串
document.createDocumentFragment
#id
document.getElementById
選擇器表達(dá)式
$(…).find
函數(shù)
注冊(cè)到dom ready的回調(diào)函數(shù)
3.3 jQuery.extend = jQuery.fn.extend
// 合并兩個(gè)或更多對(duì)象的屬性到第一個(gè)對(duì)象中,jQuery后續(xù)的大部分功能都通過(guò)該函數(shù)擴(kuò)展
// 通過(guò)jQuery.fn.extend擴(kuò)展的函數(shù),大部分都會(huì)調(diào)用通過(guò)jQuery.extend擴(kuò)展的同名函數(shù)
// 如果傳入兩個(gè)或多個(gè)對(duì)象,所有對(duì)象的屬性會(huì)被添加到第一個(gè)對(duì)象target
// 如果只傳入一個(gè)對(duì)象,則將對(duì)象的屬性添加到j(luò)Query對(duì)象中。
// 用這種方式,我們可以為jQuery命名空間增加新的方法??梢杂糜诰帉?xiě)jQuery插件。
// 如果不想改變傳入的對(duì)象,可以傳入一個(gè)空對(duì)象:$.extend({}, object1, object2);
// 默認(rèn)合并操作是不迭代的,即便target的某個(gè)屬性是對(duì)象或?qū)傩?,也?huì)被完全覆蓋而不是合并
// 第一個(gè)參數(shù)是true,則會(huì)迭代合并
// 從object原型繼承的屬性會(huì)被拷貝
// undefined值不會(huì)被拷貝
// 因?yàn)樾阅茉颍琂avaScript自帶類型的屬性不會(huì)合并
// jQuery.extend( target, [ object1 ], [ objectN ] )
// jQuery.extend( [ deep ], target, object1, [ objectN ] )
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
// 如果第一個(gè)參數(shù)是boolean型,可能是深度拷貝
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
// 跳過(guò)boolean和target,從第3個(gè)開(kāi)始
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
// target不是對(duì)象也不是函數(shù),則強(qiáng)制設(shè)置為空對(duì)象
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
// 如果只傳入一個(gè)參數(shù),則認(rèn)為是對(duì)jQuery擴(kuò)展
if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
// 只處理非空參數(shù)
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
// 避免循環(huán)引用
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
// 深度拷貝且值是純對(duì)象或數(shù)組,則遞歸
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
// 如果copy是數(shù)組
if ( copyIsArray ) {
copyIsArray = false;
// clone為src的修正值
clone = src && jQuery.isArray(src) ? src : [];
// 如果copy的是對(duì)象
} else {
// clone為src的修正值
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
// 遞歸調(diào)用jQuery.extend
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
// 不能拷貝空值
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
// 返回更改后的對(duì)象
return target;
};
未完待續(xù)
畢竟是邊讀邊寫(xiě),不對(duì)的地方請(qǐng)告訴我,多多交流共同進(jìn)步。本章還未寫(xiě)完,完了會(huì)提交PDF。
前記:
想系統(tǒng)的好好寫(xiě)寫(xiě),但是會(huì)先從感興趣的部分開(kāi)始。
近期有讀者把PDF傳到了百度文庫(kù)上,首先感謝轉(zhuǎn)載和傳播,但是據(jù)為已有并設(shè)置了挺高的財(cái)富值才能下載就不好了,以后我整理好了會(huì)傳到文庫(kù)上。請(qǐng)?bào)w諒一下。
3. 構(gòu)造jQuery對(duì)象
3.1 源碼結(jié)構(gòu)
先看看總體結(jié)構(gòu),再做分解:
復(fù)制代碼 代碼如下:
(function( window, undefined ) {
var jQuery = (function() {
// 構(gòu)建jQuery對(duì)象
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
// jQuery對(duì)象原型
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
// selector有以下7種分支情況:
// DOM元素
// body(優(yōu)化)
// 字符串:HTML標(biāo)簽、HTML字符串、#id、選擇器表達(dá)式
// 函數(shù)(作為ready回調(diào)函數(shù))
// 最后返回偽數(shù)組
}
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
// 合并內(nèi)容到第一個(gè)參數(shù)中,后續(xù)大部分功能都通過(guò)該函數(shù)擴(kuò)展
// 通過(guò)jQuery.fn.extend擴(kuò)展的函數(shù),大部分都會(huì)調(diào)用通過(guò)jQuery.extend擴(kuò)展的同名函數(shù)
jQuery.extend = jQuery.fn.extend = function() {};
// 在jQuery上擴(kuò)展靜態(tài)方法
jQuery.extend({
// ready bindReady
// isPlainObject isEmptyObject
// parseJSON parseXML
// globalEval
// each makeArray inArray merge grep map
// proxy
// access
// uaMatch
// sub
// browser
});
// 到這里,jQuery對(duì)象構(gòu)造完成,后邊的代碼都是對(duì)jQuery或jQuery對(duì)象的擴(kuò)展
return jQuery;
})();
window.jQuery = window.$ = jQuery;
})(window);
l jQuery對(duì)象不是通過(guò) new jQuery 創(chuàng)建的,而是通過(guò) new jQuery.fn.init 創(chuàng)建的
復(fù)制代碼 代碼如下:
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
n jQuery對(duì)象就是jQuery.fn.init對(duì)象
n 如果執(zhí)行new jQeury(),生成的jQuery對(duì)象會(huì)被拋棄,最后返回 jQuery.fn.init對(duì)象;因此可以直接調(diào)用jQuery( selector, context ),沒(méi)有必要使用new關(guān)鍵字
l 先執(zhí)行 jQuery.fn = jQuery.prototype,再執(zhí)行 jQuery.fn.init.prototype = jQuery.fn,合并后的代碼如下:
jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
所有掛載到j(luò)Query.fn的方法,相當(dāng)于掛載到了jQuery.prototype,即掛載到了jQuery 函數(shù)上(一開(kāi)始的 jQuery = function( selector, context ) ),但是最后都相當(dāng)于掛載到了 jQuery.fn.init.prototype,即相當(dāng)于掛載到了一開(kāi)始的jQuery 函數(shù)返回的對(duì)象上,即掛載到了我們最終使用的jQuery對(duì)象上。
這個(gè)過(guò)程非常的繞,金玉其外“敗絮”其中??!
3.2 jQuery.fn.init
jQuery.fn.init的功能是對(duì)傳進(jìn)來(lái)的selector參數(shù)進(jìn)行分析,進(jìn)行各種不同的處理,然后生成jQuery對(duì)象。
類型(selector)
處理方式
DOM元素
包裝成jQuery對(duì)象,直接返回
body(優(yōu)化)
從document.body讀取
單獨(dú)的HTML標(biāo)簽
document.createElement
HTML字符串
document.createDocumentFragment
#id
document.getElementById
選擇器表達(dá)式
$(…).find
函數(shù)
注冊(cè)到dom ready的回調(diào)函數(shù)
3.3 jQuery.extend = jQuery.fn.extend
復(fù)制代碼 代碼如下:
// 合并兩個(gè)或更多對(duì)象的屬性到第一個(gè)對(duì)象中,jQuery后續(xù)的大部分功能都通過(guò)該函數(shù)擴(kuò)展
// 通過(guò)jQuery.fn.extend擴(kuò)展的函數(shù),大部分都會(huì)調(diào)用通過(guò)jQuery.extend擴(kuò)展的同名函數(shù)
// 如果傳入兩個(gè)或多個(gè)對(duì)象,所有對(duì)象的屬性會(huì)被添加到第一個(gè)對(duì)象target
// 如果只傳入一個(gè)對(duì)象,則將對(duì)象的屬性添加到j(luò)Query對(duì)象中。
// 用這種方式,我們可以為jQuery命名空間增加新的方法??梢杂糜诰帉?xiě)jQuery插件。
// 如果不想改變傳入的對(duì)象,可以傳入一個(gè)空對(duì)象:$.extend({}, object1, object2);
// 默認(rèn)合并操作是不迭代的,即便target的某個(gè)屬性是對(duì)象或?qū)傩?,也?huì)被完全覆蓋而不是合并
// 第一個(gè)參數(shù)是true,則會(huì)迭代合并
// 從object原型繼承的屬性會(huì)被拷貝
// undefined值不會(huì)被拷貝
// 因?yàn)樾阅茉颍琂avaScript自帶類型的屬性不會(huì)合并
// jQuery.extend( target, [ object1 ], [ objectN ] )
// jQuery.extend( [ deep ], target, object1, [ objectN ] )
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
// 如果第一個(gè)參數(shù)是boolean型,可能是深度拷貝
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
// 跳過(guò)boolean和target,從第3個(gè)開(kāi)始
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
// target不是對(duì)象也不是函數(shù),則強(qiáng)制設(shè)置為空對(duì)象
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
// 如果只傳入一個(gè)參數(shù),則認(rèn)為是對(duì)jQuery擴(kuò)展
if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
// 只處理非空參數(shù)
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
// 避免循環(huán)引用
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
// 深度拷貝且值是純對(duì)象或數(shù)組,則遞歸
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
// 如果copy是數(shù)組
if ( copyIsArray ) {
copyIsArray = false;
// clone為src的修正值
clone = src && jQuery.isArray(src) ? src : [];
// 如果copy的是對(duì)象
} else {
// clone為src的修正值
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
// 遞歸調(diào)用jQuery.extend
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
// 不能拷貝空值
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
// 返回更改后的對(duì)象
return target;
};
未完待續(xù)
相關(guān)文章
jQuery實(shí)現(xiàn)可以控制圖片旋轉(zhuǎn)角度效果(附demo源碼下載)
這篇文章主要介紹了jQuery實(shí)現(xiàn)可以控制圖片旋轉(zhuǎn)角度效果,可實(shí)現(xiàn)通過(guò)下方的滑塊拖動(dòng)控制圖片旋轉(zhuǎn)的功能,涉及jQuery操作頁(yè)面元素樣式動(dòng)態(tài)變換的技巧,并附帶demo源碼供讀者下載,需要的朋友可以參考下2016-01-01基于jQuery的輸入框無(wú)值自動(dòng)顯示指定數(shù)據(jù)的實(shí)現(xiàn)代碼
在自己的網(wǎng)頁(yè)中,常常要實(shí)現(xiàn)指定樣式的輸入框,當(dāng)輸入框中沒(méi)有輸入或只輸入空格等無(wú)效信息時(shí),自動(dòng)顯示指定的文本,以提醒用戶應(yīng)該如何操作,下面是具體實(shí)現(xiàn)方法,僅供參考。2011-01-01基于jquery DOM寫(xiě)的類似微博發(fā)布的效果
看了上個(gè)原生js DOM版的微博發(fā)布的效果,再來(lái)看看如何用jq寫(xiě)。看完代碼,就會(huì)發(fā)現(xiàn)jq的強(qiáng)大,用更少的代碼寫(xiě)更多的效果2012-10-10jQuery實(shí)現(xiàn)倒計(jì)時(shí)功能完整示例
這篇文章主要介紹了jQuery實(shí)現(xiàn)倒計(jì)時(shí)功能,結(jié)合完整實(shí)例形式詳細(xì)分析了jQuery倒計(jì)時(shí)功能相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下2020-06-06基于jQuery Tipso插件實(shí)現(xiàn)消息提示框特效
這篇文章主要介紹了基于jQuery Tipso插件實(shí)現(xiàn)消息提示框特效,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-03-03jQuery制作網(wǎng)頁(yè)版選項(xiàng)卡
這篇文章主要為大家詳細(xì)介紹了jQuery制作網(wǎng)頁(yè)版選項(xiàng)卡的相關(guān)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07jQuery實(shí)現(xiàn)的兩種簡(jiǎn)單彈窗效果示例
這篇文章主要介紹了jQuery實(shí)現(xiàn)的兩種簡(jiǎn)單彈窗效果,結(jié)合實(shí)例形式分析了jQuery實(shí)現(xiàn)淡入彈窗及滑動(dòng)彈窗的相關(guān)操作技巧,需要的朋友可以參考下2018-04-04