jquery是前端常用的庫,它的源碼也是十分的精妙,我本著敬畏之心來分析它,jquery 代碼未壓縮總共有11009行,這么多的代碼一行一行的看下去不知道要看到猴年馬月,為何不換一種方式,我們先掌握它的主干,以后有時(shí)間再去研究它的各個(gè)分支,在此,我們采用猜想實(shí)驗(yàn)法
-
第一個(gè)問題:$(),$.each(),$('body')等,為什么他們這樣寫就有效果,大家可以想到了 $肯定是個(gè)函數(shù),$('body')就是執(zhí)行這個(gè)函數(shù),那么所謂的$.each,$.ajax 應(yīng)該是這個(gè)函數(shù)的屬性或是方法,那么來嘗試寫一個(gè)最簡單的構(gòu)造函數(shù)
var hQuery =function (selector, context){ } hQuery.prototype= { sayHello:function(){ console.log('hello world') } } window.$= hQuery //將函數(shù)hQuery綁定全局對(duì)象window的屬性
這樣 $()就等同于 執(zhí)行 函數(shù) hQuery(),但是這時(shí)還是不行,我們只能用 new $('div')來生成不同的實(shí)例對(duì)象來操作,那怎么才能把new 給去調(diào),那么我們肯定是想到的思路是 我讓 hQuery 返回一個(gè)新的對(duì)象,不就不用 new 來生成了新的對(duì)象,好吧,我們來試一試,
var hQuery =function (selector, context){
return this
}
hQuery.prototype= {
sayHello:function(){
console.log('hello world')
}
}
return this 執(zhí)行后發(fā)現(xiàn)失敗了,原來this指向的不是函數(shù)構(gòu)造函數(shù)本身,this 指向的是全局對(duì)象window,怎么辦才能讓它返回一個(gè)新的對(duì)象,要不試一試 返回 對(duì)象的原型,于是我們繼續(xù)嘗試
var hQuery =function (selector, context){
return hQuery.prototype
}
hQuery.prototype= {
sayHello:function(){
console.log('hello world')
}
}-
這樣執(zhí)行后雖然返回了一個(gè)對(duì)象,但是生成的所有對(duì)象都是繼承hQuery.prototype,對(duì)象都是一樣的,這不是我們的通過構(gòu)造函數(shù)返回不同的對(duì)象的目標(biāo),又失敗了,怎么辦,于是我們想到能不能在原型里綁定個(gè)方法函數(shù)(構(gòu)造函數(shù)也能生產(chǎn)實(shí)例),并返回函數(shù)方法的原型,
var hQuery= function(selector,context){
return new hQuery.prototype.init.(selector,context)
};hQuery.prototype = { init:function(selector,context){ console.log(this === hQuery.prototype);//false return this //此時(shí)this指向init{} }, sayHello:function (){ console.log('hello world') } }; window.hQuery= window.$= hQuery -
執(zhí)行后還是不行,不同的對(duì)象是生成了,可是不能調(diào)用hQuery的原型的方法,怎么才能讓生成的init屬性的構(gòu)造函數(shù)生成的對(duì)象繼承hQuery.prototype里的方法了,于是讓前者繼者后者的原型試一試
var hQuery= function(selector,context){return new hQuery.prototype.init(selector,context) }; hQuery.prototype = { constructor:hQuery, init:function(selector,context){ this.selector= selector; this.context=context; }, sayHello:function(){ console.log('hello') } }; hQuery.prototype.init.prototype = hQuery.prototype window.hQuery= window.$= hQuery 執(zhí)行后成功了,成功的生成不同的對(duì)象,這是因?yàn)閕nit 方法構(gòu)造函數(shù)經(jīng)過new 后生成了不同的函數(shù),同時(shí)它的原型此時(shí)指向了hQuery.prototype,也繼承了hQuery的方法,我們終于實(shí)現(xiàn)了$()傳入?yún)?shù)的不同,生成不同的對(duì)象,公用一套方法。
原型鏈圖

- 雖然已經(jīng)這種方法已經(jīng)實(shí)現(xiàn)了,你也就應(yīng)該知道了jquery鏈?zhǔn)秸{(diào)用的原理了把,就是給我往hQuery.prototype上添加公用的方法,再用return this,把對(duì)象返回出來,然后按這樣的流程執(zhí)行下個(gè)方法
var hQuery= function(selector,context){
return new hQuery.prototype.init(selector,context)
};
hQuery.prototype = {
constructor:hQuery,
init:function(selector,context){
this.selector= selector;
this.context=context;
},
sayHello:function(){
console.log('hello')
return this;
},
addClass:function(el){
console.log('addClass: '+el)
return this;
}
};
hQuery.prototype.init.prototype = hQuery.prototype - 所以每個(gè)方法必須要return this(init構(gòu)造函數(shù)生成的對(duì)象) 后才能讓下一個(gè)方法繼續(xù)執(zhí)行。
- 但是到現(xiàn)在還沒有實(shí)現(xiàn)$.ajax,$.each,這種形式的調(diào)用,不過現(xiàn)在實(shí)現(xiàn)這個(gè)太簡單了,我直接在函數(shù)上添加方法不就行了
hQuery.ajax =function (){
console.log('ajax execute!')
};
$.ajax() - 可是感覺太丑了,不美觀,必須一個(gè)一個(gè)方法這樣把它添加上,參考jquery的拷貝extend,做個(gè)超級(jí)簡單版本
hQuery.extend = hQuery.prototype.extend =function (obj){
for( var key in obj){
this[key]=obj[key]
}
}; - 此時(shí)extend方法遍歷了傳遞參數(shù)0bj的所有屬性,并把obj的屬性屬性賦值給 hQuery.prototype或hQuery.extend,我們直接使用extend 的方法添加方法和屬性
hQuery.extend({
isArray: Array.isArray,
ajax:function(){}
});
hQuery.prototype.extend({
addClass:function(){console.log('add class....')},
sayHello:function(){
console.log('hello'+this.selector)
}
}) - 到此為止,我們終于實(shí)現(xiàn)了jquery的超級(jí)簡單傻瓜版,全部代碼如下:
var hQuery= function(selector,context){
return new hQuery.prototype.init(selector,context)
};
hQuery.prototype = {
constructor:hQuery,
init:function(selector,context){
this.selector= selector;
this.context=context;
},
sayHello:function(){
console.log('hello')
return this;
},
addClass:function(el){
console.log(this)
console.log('addClass: '+el)
return this;
}
};
hQuery.prototype.init.prototype = hQuery.prototype
hQuery.extend = hQuery.prototype.extend =function (obj){
for( var key in obj){
this[key]=obj[key]
}
};
hQuery.extend({
isArray: Array.isArray,
ajax:function(){}
});
hQuery.prototype.extend({
saySelector:function(){
console.log(this.selector)
}
}) - 后記:jquery博大精深,自己只是懂了最最簡單的實(shí)現(xiàn),今后還要認(rèn)真學(xué)習(xí)和分析它的源碼