最近在讀underscore源碼的時候精刷,又遇見了需要隱式new構(gòu)建的模式撼班,雖然之前有過了解,但是并未記得败许,所以在網(wǎng)上找攻略王带,然后現(xiàn)在將自己的心得寫出來,也一方面或許能對他人有所幫助市殷。(一般來講是無new愕撰,但是我認(rèn)為這會誤導(dǎo)理解,所以我在本文中所用是隱式new,原因我會在下面說搞挣,且本文主要針對的是對類庫的架構(gòu)有興趣且已經(jīng)對JavaScript有一定了解的讀者带迟。)
一般來說,我們會在script標(biāo)簽內(nèi)中這樣使用jQuery囱桨。
$('#demo').html('hello');//創(chuàng)建一個jQuery實例仓犬,然后返回這個實例并進(jìn)行操作。
或者你也可以這樣
var demo =new $('#demo');
demo.html('hello');
我認(rèn)為在日常的使用中舍肠,大部分人都會選擇用第一種方法搀继,因為簡單且便捷,其實$('')和new $('')所發(fā)生的事情是一樣的貌夕,那么我們來看看在jQuery內(nèi)部是如何架構(gòu)的律歼。
(function (window, undefined) {
var jQuery = function(selector, context) {
// 返回一個jQuery原型下的init方法的實例
return new jQuery.fn.init(selector, context, rootjQuery);
},
jQuery.fn = jQuery.prototype = {
init: function(selector, context, rootjQuery) {
// ...
}
}
jQuery.fn.init.prototype = jQuery.fn;
window.$===undefined&&(window.$=jQuery);
})(window);
那么我們先不要急著理解上面的代碼,現(xiàn)在我們來一步步理解為什么要這樣寫啡专。
1.我們要做的第一件事是我們需要有一個東西用來返回實例。那么我們可能會這樣做:
var jQuery = function(selector, context) {
return new jQuery();
}
jQuery.prototype = {
name:'Bertie',
age:function(age){
return age;
}
}
雖然可以了制圈,但是這樣就會造成死循環(huán)们童,那么我們就需要轉(zhuǎn)變思路,其實我們可以把jQuery類當(dāng)作一個工廠方法來創(chuàng)建實例鲸鹦,把這個方法放到j(luò)Query原型中:
var jQuery = function(selector, context) {
return jQuery.prototype.init(selector);
}
jQuery.prototype = {
// ...
}
但是如今又有一個缺陷慧库,那么就是只生成了一個實例,并且在實際使用中馋嗜,肯定不止一個要實例一個對象了齐板,有#demo,就會有#demo2.#demo3...葛菇,那么咱們需要對以上的代碼做一點修改:
var jQuery = function(selector, context) {
return new jQuery.prototype.init(selector);
}
jQuery.prototype = {
init:function (param) {
if (param instance String) {
this.name=param;
}
return this;//將jQuery實例用原型下的init代替實例化
},
name:'',
age:''
}
這樣就可以隔離不同的this作用域甘磨,需要用到new 而不是直接返回jQuery.prototype.init(seletor);,每調(diào)用(每實例一次)就會創(chuàng)建一個新的this作用域眯停。
那么我們就剩下最后一件事情要做了就是济舆,init上沒有我們想要的屬性和方法,就是我們想把屬性和方法放到j(luò)Query的原型下莺债,而不是init原型下滋觉,因為在每次調(diào)用的時候,可以不用多在原型鏈上在多找一層(如果將屬性和方法放在init上的話)齐邦,并且對性能也有提升椎侠,那我們就這樣干吧:jQuery.prototype.init.prototype = jQuery.prototype:
(function (window, undefined) {
var jQuery = function(selector, context) {
return new jQuery.fn.init(selector, context, rootjQuery);
},
jQuery.fn = jQuery.prototype = {
init: function(selector, context, rootjQuery) {
// ...
}
}
jQuery.fn.init.prototype = jQuery.fn;
window.$===undefined&&(window.$=jQuery);
})(window);
現(xiàn)在再回到j(luò)Query的源碼來看的話是不是就可以若然開朗了呢?
到現(xiàn)在或許你也明白了為什么我說無new會誤導(dǎo)理解了吧措拇,的確需要用new實例化了我纪,但是不是jQuery本體,而是jQuery原型上的某個方法。
題后話
一直都想寫自己的技術(shù)博客宣羊,但是一直都在拖延璧诵,因為現(xiàn)在在讀underscore的源碼,然后想把整個學(xué)習(xí)過程記錄下來仇冯,之后我會一步步更新我學(xué)習(xí)underscore的源碼精髓之宿,當(dāng)然,還有我所擅長的重構(gòu)和性能優(yōu)化領(lǐng)域苛坚,和有趣的前端知識比被,也都會分享到我的簡書中,so泼舱,c u next time :)等缀。