不用構造函數(Constructor)new關鍵字也能實現JavaScript的面向對象
2024-05-06 14:19:57
供稿:網友
JavaScript中的對象模型(object model)并不廣為人知。我曾寫過一篇關于他們的博客。之所以不被人所熟知,原因之一就是JavaScript是這些被人廣泛使用的語言中唯一一個通過原型(prototype)來實現繼承的。但是,我認為另一個原因就是這種對象模型非常復雜,難于解釋。它為什么這么復雜并且又令人困惑呢?那是因為JavaScript試圖去隱藏它傳統的面向對象的特性——最終導致了它的雙重人格(譯者注:作者意思是JavaScript既有面向過程的特征,又有面向對象的特征)。
我認為正是由于JavaScript對象模型的難以理解和使用,才出現了一些像CoffeeScript,Dart和TypeScript這些通過編譯可以生成JS代碼的語言。
JavaScript的前輩們和那些頑固派相信JavaScript有更好的對象模型,并且為其將被大家所遺忘感到惋惜。即使JavaScript的專家Nicholas Zakas也歡迎在ECMAScript 6中加入的新的class語法——只不過是對原型風格(prototypal style)的語法做了一些修飾。換句話說,傳統的OOP贏了。
一個大膽的設想
但是,讓我們以玩笑的方式做一個設想:我們假想穿越到過去,那時候傳統的面向對象的程序設計還沒有像現在這樣被大家廣泛的接受,相反的,基于原型的繼承模型得到了大家的廣泛接受。這樣的話會發生什么?我們最終又會得到些什么樣的設計模式呢?
我們再設想:假設JavaScript沒有構造函數或者沒有new關鍵字會怎樣?事情又會變成什么樣的呢?讓我們推到以前的重來。:)
首先,第一件事情,在JavaScript中,我們可以使用對象字面量的來創建一個新對象。如下所示:
代碼如下:
var felix = {
name: 'Felix',
greet: function(){
console.log('Hello, I am ' + this.name + '.');
}
};
接下來,假設我們想要將greet函數一般化,將其提取出來,放到一個一般的位置,這樣一來,我們就可以創建多個對象來共享同一個greet方法。該怎么實現呢?
我們有好幾種選擇,先以mixin開始吧。
1、混入(對象擴張)Mixin(Augmentation)
在JavaScript語言中,混入屬性非常簡單。你只需要將混入對象的屬性復制到要混入的對象中去即可。我們將使用一個“augment”函數來實現它,看代碼就明白了:
代碼如下:
var Dude = {
greet: function(){
console.log('Hello, I am ' + this.name + '.')
}
};
var felix = { name: 'Felix' };
augment(felix, Dude);//將Dude中的屬性復制一份到felix中,即混入(mixin)
在上面的代碼中,augment函數將Dude對象的屬性混入到了felix當中。在很多的JS庫中,augment函數被叫做extend。我不喜歡用extend,因為一些語言用extend表示繼承,以至于是我很困惑。我更喜歡用“augment”表示,因為實際上這種做法并不是繼承,并且語法augment(felix, Dude)已經很清楚的表明你是用Dude中的屬性對felix進行了擴充,而不是繼承。