天天看點

(Javascript)prototype的一個優勢也是...

如何在 Javascript 實作 OO 程式設計?恐怕最好的方式就是充分利用 prototype 屬性。關于 prototype 的介紹有很多,我就不贅述了。比較基本的原理是,當你用 prototype 編寫一個類後,當你 new 一個新的 object ,浏覽器會自動把 prototype 中的内容替你附加在 object 上。這樣,通過利用 prototype ,你也就實作了類似 OO 的 Javascript 。

在 Javascript 中, object 就是一個 associative array 。一個 function 就是一個類。當你編寫如下 function 時,其實就是定義了一個類,該 function 就是它的構造函數。

function MyObject(name, size)

       {

              this.name = name;

              this.size = size;

       }

之後,你可以友善的通過 MyObject 類的 prototype 屬性來友善的擴充它。比如,你可以給他添加其他的屬性和方法。

       MyObject.prototype.tellSize = function()

       {

              return "size of "+this.name+" is "+this.size;

       }

       MyObject.prototype.color = "red";

       MyObject.prototype.tellColor = function()

       {

              return "color of "+this.name+" is "+this.color;

       }

       var myobj1 = new MyObject("tiddles", "7.5 meters");

       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

你可以想象,當你調用 tellColor() 方法後,結果是這樣的:

color of tiddles is red

很友善的是, prototype 屬性可以動态添加。比如,你需要往 MyObject 中加入一個 height 屬性,并希望其提供一個 tellHeight() 方法來獲得 height 屬性的值。你可以在上面的代碼後,繼續添加如下的代碼:

       MyObject.prototype.height = "2.26 meters";

       MyObject.prototype.tellHeight = function()

       {

              return "height of "+this.name+" is "+this.height;

       }

之後,你可以通路一下 myobj1 的 tellHeight() 方法,你可以得到如下的結果:

height of tiddles is 2.26 meters

prototype 的這些動态的特性看起來有些迷人,不過我倒是反而覺得有些涼飕飕的。确實,這些特性給你很大的靈活性,可以給與你 runtime 改變類屬性和方法的能力。不過,稍微發掘一下,會有些不良的習慣産生。

首先,如果可以動态添加屬性和方法,那麼很容易讓人想到,當我調用時,我想要調用的屬性或者方法存在不?這是一個很嚴肅的問題,如果當我們調用時根本沒有該屬性或者方法,将可能導緻我們的腳本 down 掉。

不過也有解決辦法。比如,在上面的代碼中,當還沒有 tellHeight() 方法時,我們可以如下編寫代碼避免發生錯誤:

       if (myobj1.tellHeight)

       {

              domDiv.innerHTML += myobj1.tellHeight()+"<br /><br />";

       }

注意,一定要在 if 語句中,不要加方法後面的那對 () ,否則,直接就 down 掉了。有興趣的讀者可以列印一下,看看分别通路 myobj1.tellHeight 和 myobj1.tellHeight() 時有什麼差別。

也許,你覺得這個是小意思。加個判斷嘛,不就好了?

對,但是下面一個問題更令人頭痛。

屬性和方法在不在的問題簡單,可是屬性和方法變不變化的問題可就嚴重了。在不在我們可以檢測,變不變呢?比如,請看下面的代碼:

       function MyObject(name, size)

       {

              this.name = name;

              this.size = size;

       }

       MyObject.prototype.color = "red";

       MyObject.prototype.tellColor = function()

       {

              return "color of "+this.name+" is "+this.color;

       }

       var myobj1 = new MyObject("tiddles", "7.5 meters");

       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

       MyObject.prototype.color = "green";

       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

該代碼将産生如下結果:

color of tiddles is red

color of tiddles is green

請注意,你修改的是類 MyObject 的 color 屬性。但是你驚奇的看到你之前執行個體化的對象 myobj1 的屬性值竟然也變化了。天!如果你的項目代碼是多人合作,那麼,也許某個人會在程式設計時為了圖一己之便,擅自修改你的類。于是,所有人的對象都變化了。于是,你們陷入了漫長的 debug 過程中。。。。。。(不要說我沒有告訴你啊)

上面是屬性,還有方法:

       function MyObject(name, size)

       {

              this.name = name;

              this.size = size;

       }

       MyObject.prototype.color = "red";

       MyObject.prototype.tellColor = function()

       {

              return "color of "+this.name+" is "+this.color;

       }

       var myobj1 = new MyObject("tiddles", "7.5 meters");

       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

       MyObject.prototype.color = "green";

       MyObject.prototype.tellColor = function()

       {

              return "your color of "+this.name+" is "+this.color;

       }

       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

這段代碼的結果是:

color of tiddles is red

your color of tiddles is green

哈?原來方法也能變,汗!

問題來了。 Javascript 太靈活的程式設計方式多少讓人不适應。如果整個 Team 的水準都比較高還可以,沒人會犯這樣的錯誤。但是,當有個毛頭小夥子不知情,擅自修改類,将導緻所有的人的對象都發生變化,無論是屬性還是方法。在 Javascript 代碼變得越來越多的 Ajax 時代,這是一個嚴重的問題。

這說明,編寫 Javascript 時,好的程式設計風格更加重要。記得某人曾經說過這樣的話,想 Java 和 C# 這些比較嚴格的語言,雖然降低了靈活性,但也減少了犯錯誤的可能。這樣,即使一個新手,他寫出的代碼也不會與高手差太多。但是,像 Javascript 這樣的腳本語言,由于太靈活,是以,高手寫出的是天使,而新手寫的,可能是魔鬼!

繼續閱讀