jQuery無(wú)new構(gòu)建實(shí)例
無(wú)new化構(gòu)建
在jQuery中 $符號(hào)就是jQuery的別稱
$()就是創(chuàng)建了jQuery的實(shí)例對(duì)象
實(shí)現(xiàn)
(function(root){
function jQuery() {
return new jQuery.prototype.init();
};
// 在jQuery的原型上定義init方法
jQuery.prototype = {
init: function() {
},
css: function() {
// 在jQuery原型上擴(kuò)展的屬性也會(huì)被共享到init的原型上
}
}
// 把jQuery的原型共享給init的原型
jQuery.prototype.init.prototype = jQuery.prototype;
// 設(shè)置全局變量$和jQuery
root.$ = root.jQuery = jQuery;
})(this); // 把宿主對(duì)象window傳進(jìn)
共享原型設(shè)計(jì)
描述
如上, 在實(shí)現(xiàn)jQuery實(shí)例化的時(shí)候,我們直接調(diào)用$();
console.log($());
因?yàn)?()指向的是jQuery函數(shù),所以相當(dāng)于調(diào)用了jQuery函數(shù);
// 設(shè)置全局變量$和jQuery;
// $和window.jQuery指向的都是jQuery函數(shù)
root.$ = root.jQuery = jQuery;
jQuery作為構(gòu)造函數(shù)直接被調(diào)用效果和普通函數(shù)唄調(diào)用一樣,
所以無(wú)法生成有效實(shí)例;
解決方案:
只能把jQuery函數(shù)的返回值設(shè)成構(gòu)造函數(shù)的實(shí)例;
function jQuery() {
return new jQuery();
};
但是這樣做是不行的,很明顯會(huì)造成死循環(huán)
所以jQuery采用的共享原型的設(shè)計(jì)模式, 即;
-
在jQuery函數(shù)的prototype上定義了init方法
// 在jQuery的原型上定義init方法 jQuery.prototype = { init: function() { } } -
把jQuery的原型共享給init
// 把jQuery的原型共享給init的原型 jQuery.prototype.init.prototype = jQuery.prototype; -
通過$()調(diào)用jQuery函數(shù)時(shí)返回一個(gè)init的實(shí)例
function jQuery() { return new jQuery.prototype.init(); }; -
給jQuery的prototype擴(kuò)展屬性的時(shí)候,由于原型共享,
所以init的原型上也會(huì)具有該擴(kuò)展屬性
jQuery.prototype = { init: function() { }, css: function() { // 在jQuery原型上擴(kuò)展的屬性也會(huì)被共享到init的原型上 } } console.log($());

以上就是jQuery無(wú)new實(shí)例化的實(shí)現(xiàn)
原型擴(kuò)展設(shè)計(jì)見下圖:

extend函數(shù)源碼解析
extend函數(shù)用法:
// 給任意對(duì)象擴(kuò)展
var obj1 = { a:1, b:2 };
var obj2 = { c: 3 };
var res = $.extend(obj1, obj2);
console.log(res); // ===> { a:1, b:2, c: 3 }
console.log(obj1); // ===> { a:1, b:2, c: 3 }
// 給$(jQuery)進(jìn)行擴(kuò)展
$.extend({
myMethod: function() {
console.log('myMethod1');
}
})
$.myMethod(); // myMethod1;
// 給$(jQuery)的實(shí)例進(jìn)行擴(kuò)展
$.fn.extend({
myMethod: function() {
console.log('myMethod2');
}
})
$().myMethod(); // myMethod2;
extend函數(shù)用于給對(duì)象進(jìn)行擴(kuò)展,給jQuery提供了插件機(jī)制
- 可以給任意對(duì)象擴(kuò)展
- 也可以給jQuery自身擴(kuò)展
注:
// $.fn指向的就是$.prototype
jQuery.fn = jQuery.prototype = {
// ......
}
- extend再jQuery中之所以既能通過$.extend調(diào)用,
又能通過$().extend調(diào)用是因?yàn)樵谠创a內(nèi)部中實(shí)現(xiàn)了
jQuery.fn.extend = jQuery.extend = function() { // ...... }
extend實(shí)現(xiàn)與分析
// extend
jQuery.fn.extend = jQuery.extend = function() {
var target = arguments[0] || {}; // target賦值為第一個(gè)參數(shù),也就是要擴(kuò)展的對(duì)象
var length = arguments.length; // 獲取參數(shù)的個(gè)數(shù)
var i = 1;
var deep = false;
var options, name, copy, src, copyIsArray, clone;
if(typeof target === 'boolean') { // 當(dāng)傳入第一個(gè)參數(shù)是boolean時(shí)
deep = target; // 把參數(shù)deep的值設(shè)置為target,即傳入的第一個(gè)參數(shù)
target = arguments[1]; // 把target(需擴(kuò)展的對(duì)象設(shè)置為第二個(gè)參數(shù))
i = 2; // i = 2,以便之后從第三個(gè)參數(shù)開始遍歷
};
if(typeof target !== 'object') { // 驗(yàn)證傳入的參數(shù)為obj
target = {};
};
if(length === i) { // 如果只有一個(gè)參數(shù),則extend方法為jQuery內(nèi)部的擴(kuò)展
target = this; // 把target的引用設(shè)置為this,指向$或者$()
i--;
};
// 淺拷貝
for( ;i < length; i++) { // boolean參數(shù)和所需要擴(kuò)展的對(duì)象的屬性無(wú)需遍歷
if((options = arguments[i]) !==null) {
for(name in options) {
copy = options[name];
src = target[name];
// 如果需要深拷貝,并且options的屬性對(duì)應(yīng)的是對(duì)象或數(shù)組時(shí)
if(deep && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
if(copyIsArray) {
copyIsArray = false; //copyIsArray不重置會(huì)影響下一次循環(huán)的判斷;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
target[name] = jQuery.extend(deep, clone, copy);
} else if(copy !== undefined) {
target[name] = copy;
};
};
};
};
return target;
}
jQuery.extend({
isPlainObject: function(obj) { // 判斷傳入?yún)?shù)的數(shù)據(jù)類型是否是obj
return toString.call(obj) === '[object Object]'
},
isArray: function(arr) { // 判斷傳入?yún)?shù)的數(shù)據(jù)類型是否是數(shù)組
return toString.call(arr) === '[object Array]'
}
});