2012年11月19日 星期一

Javascript is OOP?

這是個會引發"聖戰"之類的話題,我想這件事情留給有能力的人去回答,退而在此討論javascript"做得到"跟"做不到"的事情

is-a關係,很多人第一刻在繼承裡面學到的。我們說objC is a objP,也就是說可以把objC當成objP一樣對待,兒子應該跟老爸有相同的四肢構造。

可以先看底下的文章,解釋如何使用javascript的prototype完成繼承
http://peter.michaux.ca/articles/transitioning-from-java-classes-to-javascript-prototypes

首先要解釋的是javascript是duck type的程式語言,很多程式語言都是duck type,也就是一個物件看起來像是鴨子(特徵attributes),走路像鴨子(methods),那麼我們就認定他是一隻鴨子

javascript藉由prototype,隨時隨地可以將一個物件的屬性跟介面加入另外一個物件裡面,讓一個物件看起來像是另外一類的物件,比方說在上面peter給的範例實作了observer pattern,如果今天我有個物件擁有update方法,那我就看起來像是observer,真的是這樣嗎?所以要預防這種事情,絕對的方式是用instanceof來檢驗update方法真的來自observer。第二個問題,跟著如果併入另外一組物件的屬性跟介面(也有update)的時候,兩個function A跟B想要的是不同型態的參數,這時候呼叫的是哪一個update??似乎兩者都可以互通,這是duck type的特性
extends(WeatherModel, Observable);
extends(WeatherModel, Observable2);<=????????????????
function A(o:Observable);<=????????????????
function B(o:Observable2);<=????????????????
可以預期的是上面的程式碼可以順利運作(一定會呼叫某個物件的update,或者某個型態的update),但是未必如你所料

回頭來看java/C++,如果今天要在程式執行期間的實作一組介面,恐怕沒有辦法,你只能期待能不能從java Reflection或者C++的pointer跟強制轉型,擠出一點希望,但反過來說,是你可以確定的是不會讓一個不該屬於某個介面的物件放進一個不應該屬於那個型態的function之內(compile time)

OO上很重的一個觀念是is-a的體現,但兩者不同的做法沒有絕對的好壞,因為OO上is-a的解釋很寬廣。從上面可以看出來java/C++是strong type,所以在這種事情上給了某種保證,但是也失去了彈性,javascript獲取了彈性(duck type),但是也付出了某種代價。
OO的體現差異,上面提到的只是兩者之間在OO方面實作差異的冰山一角,希望能對大家在OO上面有進一步的體驗。

Peter的文章告訴我們不要從語言上面學習OO是個很重要的觀念,同時了解語言的差異在體現OO的特性上也很有幫助。對於學習OO觀念,或許從CRC卡上著手是個不錯的開始

可是也別太過極端,認為任何程式語言都可以實作OO,那恐怕是程度上的區別。不要被程式語言綁架了體現OO的作法,但一個程式語言號稱是OOP亦有他的道理

P.S. 網路上爬了一堆號稱javascript繼承實作的方式(甚至多重繼承),請仔細檢驗,是否能夠達成呼叫super class的constructor?是否能使用super class的variable?這往往跟我們直覺不大一樣,一旦在sub class/instance 呼叫了super class的method,其中帶有super class的variable,很快地會看到interpreter跟你抱怨,那個method不是一個function(奇怪吧!)
比方說下面這個網址的實作,至少就犯了兩三個錯誤
www.amirharel.com/2010/06/11/implementing-multiple-inheritance-in-javascript/

下面是一個例子,討論串中有它的問題
http://www.steinbit.org/words/programming/multiple-inheritance-in-javascript

沒有留言:

張貼留言