接上一篇"原型類"
來聊聊JavaScript核心之"原型類
繼續(xù)上篇中我們的例子,拿到的是原型類
var Car = function(loc) {
var obj = Object.create(Car.prototype);
obj.loc = loc;
return obj;};
Car.prototype.move = function(){ this.loc++; };
現(xiàn)在我們把它重構(gòu)成一種與之相似的模式-偽類模式院峡。稱它為偽類兴使,是因為它仿照其他語言中的類系統(tǒng),試圖增添一些語法上的便利照激,如果我們要在程序中構(gòu)造大量的類发魄,那將會產(chǎn)生大量的重復(fù)代碼,而語言本身可以通過某種方式自動實現(xiàn)一些步驟俩垃。
看上面這個列子励幼,你認為哪些代碼是每個類都需要的并且有可能通過語言實現(xiàn)自動化的呢?沒錯口柳,就是這兩行
var obj = Object.create(Car.methods);return obj;
每個類都要創(chuàng)建一個對象苹粟,并且確保這個對象被委托到原型對象,并且返回這個對象跃闹。即這些行為會發(fā)生在每一個原型類中六水。
為了簡化輸入JavaScript提供了關(guān)鍵字new ,當我們在一個函數(shù)調(diào)用前使用關(guān)鍵字new辣卒,該函數(shù)便會以一種特殊的模式--構(gòu)造模式來運行掷贾。在此模式中,JavaScript可以自動完成這些工作荣茫。所謂構(gòu)造模式想帅,及時指解釋器在你的代碼中嵌入幾行操作代碼,因為它知道無論何時實例化一個新對象啡莉,你都需要這些被自動完成港准。它會暫時性的使你的函數(shù)運行一些額外的代碼,即使你從未輸入這些代碼咧欣。這些被插入的代碼基本上與你之前再原型類里寫的代碼一樣浅缸,那么因為我們在ben的創(chuàng)建的時候使用了關(guān)鍵字new,所以Car的調(diào)用會運行這些被插入在開頭和結(jié)尾的額外操作。
而對于amy的創(chuàng)建魄咕,我們并沒有使用關(guān)鍵字new 在Car調(diào)用的前面衩椒,所以并不會插入前面的這些代碼。所以此時在相同的程序里哮兰,這個類函數(shù)會以插入或者未被插入這些代碼的方式運行毛萌。這些插入的代碼不會在你的代碼中顯示。它們只有在調(diào)用前面使用關(guān)鍵字new時喝滞,作為這種特殊調(diào)用的結(jié)果才會被執(zhí)行阁将。但是即使這里展示了兩行代碼,一行有關(guān)鍵字new右遭,一行沒有關(guān)鍵字new做盅,但是你在寫程序時不應(yīng)如此缤削。你應(yīng)該決定一個函數(shù)是使用new關(guān)鍵字,還是不使用new關(guān)鍵字吹榴。它的目的是讓你跳過一些你已經(jīng)做的工作僻他。所以如果你決定使用new,就需要再對代碼進行一些必要的重構(gòu)。
this=Object.create(Car.prototype);/*...*/return this;
這行代碼創(chuàng)建了一個將原型委托在Car.prototype中的對象腊尚,并且賦值給this吨拗,后面又返回this。這樣即使你沒有再程序中寫出這行代碼婿斥,解釋器也可以把值賦給關(guān)鍵字this劝篷。這非常合理,并且與我們理解的關(guān)鍵字this的使用是一致的民宿,關(guān)鍵字this的用途是作為一種便捷的方式去指代一些面向?qū)ο蠛瘮?shù)調(diào)用中的任何目標對象娇妓,而 var amy = new Car(1); 這個函數(shù)的調(diào)用就是面向?qū)ο蟮模淠康氖菢?gòu)造一個新的對象活鹰。這就非常合理哈恰,無論新對象是什么,都能成為關(guān)鍵字this指代的目標志群。因此重構(gòu)后的代碼
var Car = function(loc) {
this = Object.create(Car.prototype);
this.loc = loc;
return this;};
Car.prototype.move = function(){ this.loc++; };
但是需要注意這兩行代碼只是并不存在的標注着绷,用來告訴我們關(guān)鍵字new做的事情。所以去掉這些標注锌云,我們的代碼就變成
var Car = function(loc) {
this.loc = loc;};
Car.prototype.move = function(){
this.loc++; };
var amy = new Car(1);
amy.move();
var ben= new Car(9);
ben.move();
這就是構(gòu)造一個偽類時所需要的代碼荠医。
此時在內(nèi)存的情況
這與之前的原型版本并沒有本質(zhì)的區(qū)別,因為偽類僅僅是在之前的原型模式之上桑涎,為了寫代碼方便加了薄薄一層語法糖彬向。那么實際上,這兩種模式之間的主要區(qū)別是JavaScript引擎實現(xiàn)性能優(yōu)化的數(shù)量攻冷,而這些優(yōu)化是偽類模式所獨有的娃胆。
我們再來看一下這個代碼,這段代碼與JS中的其他類模式一樣等曼,有兩個獨立區(qū)分的部分里烦,這存在之前的每一個偽類模式、原型模式以及函數(shù)共享模式之中涉兽。
在第2部分招驴,是指定一個類中的所有實例應(yīng)該相似的部分篙程,在偽類模式中這些相似的部分一般會被存儲為prototype對象的屬性枷畏。在第1部分,你可以指定每個實例和其他實例之間的不同之處虱饿。如果大部分語言拥诡,這部分寫在構(gòu)造函數(shù)體內(nèi)触趴,它允許我們指定一個類的實例和另一個這個類的實例之間的不同。所有指定的arm和ben不同是的屬性loc都是在構(gòu)造函數(shù)內(nèi)完成的渴肉。了解這兩部分代碼在每一個類中的存在冗懦,對于理解子類的概念非常重要。我下一篇會寫偽類子類的概念仇祭。
JavaScript中支持多種不同的類模式披蕉,那么應(yīng)該使用哪一種模式或者說哪一種是最好的模式,這么問他并沒有答案乌奇。作為一門語言没讲,JavaScript并沒有鮮明的立場,它更傾向于展現(xiàn)其本質(zhì)的特征礁苗,以便程序員靈活運用爬凑。因此并不存在對與錯,只是技術(shù)和選擇上的不同试伙。我們能做的是了解每一種類模式的優(yōu)點和缺點嘁信,來幫我們判斷在特定的情況下應(yīng)該使用哪種模式。
作者:長夢未央
圖片來源:優(yōu)達學(xué)城付費課程
個別文字摘自教學(xué)視頻老師的講解