怎么在Javascript實(shí)現(xiàn)OO編程?恐怕最佳的方式就是充分利用prototype屬性。關(guān)于prototype的介紹有非常多,我就不贅述了。比較基本的原理是,當(dāng)你用prototype編寫(xiě)一個(gè)類(lèi)后,當(dāng)你new一個(gè)新的object,瀏覽器會(huì)自動(dòng)把prototype中的內(nèi)容替你附加在object上。這樣,通過(guò)利用prototype,你也就實(shí)現(xiàn)了類(lèi)似OO的Javascript。
在Javascript中,object就是個(gè)associative array。一個(gè)function就是個(gè)類(lèi)。當(dāng)你編寫(xiě)如下function時(shí),其實(shí)就是定義了一個(gè)類(lèi),該function就是他的構(gòu)造函數(shù)。
function MyObject(name, size)
{
this.name = name;
this.size = size;
}
之后,你能方便的通過(guò)MyObject類(lèi)的prototype屬性來(lái)方便的擴(kuò)充他。比如,你能給他添加其他的屬性和方法。
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 />";
你能想象,當(dāng)你調(diào)用tellColor()方法后,結(jié)果是這樣的:
color of tiddles is red
非常方便的是,prototype屬性能動(dòng)態(tài)添加。比如,你需要往MyObject中加入一個(gè)height屬性,并希望其提供一個(gè)tellHeight()方法來(lái)獲得height屬性的值。你能在上面的代碼后,繼續(xù)添加如下的代碼:
MyObject.prototype.height = "2.26 meters";
MyObject.prototype.tellHeight = function()
{
return "height of "+this.name+" is "+this.height;
}
之后,你能訪問(wèn)一下myobj1的tellHeight()方法,你能得到如下的結(jié)果:
height of tiddles is 2.26 meters
prototype的這些動(dòng)態(tài)的特性看起來(lái)有些迷人,不過(guò)我倒是反而覺(jué)得有些涼颼颼的。確實(shí),這些特性給你非常大的靈活性,能給和你runtime改動(dòng)類(lèi)屬性和方法的能力。不過(guò),稍微發(fā)掘一下,會(huì)有些不良的習(xí)慣產(chǎn)生。
首先,如果能動(dòng)態(tài)添加屬性和方法,那么非常容易讓人想到,當(dāng)我調(diào)用時(shí),我想要調(diào)用的屬性或方法存在不?這是個(gè)非常嚴(yán)肅的問(wèn)題,如果當(dāng)我們調(diào)用時(shí)根本沒(méi)有該屬性或方法,將可能導(dǎo)致我們的腳本down掉。
不過(guò)也有解決辦法。比如,在上面的代碼中,當(dāng)還沒(méi)有tellHeight()方法時(shí),我們能如下編寫(xiě)代碼避免發(fā)生錯(cuò)誤:
if (myobj1.tellHeight)
{
domDiv.innerHTML += myobj1.tellHeight()+"<br /><br />";
}
注意,一定要在if語(yǔ)句中,不要加方法后面的那對(duì)(),否則,直接就down掉了。有興趣的讀者能打印一下,看看分別訪問(wèn)myobj1.tellHeight和myobj1.tellHeight()時(shí)有什么差別。
也許,你覺(jué)得這個(gè)是小意思。加個(gè)判斷嘛,不就好了?
對(duì),不過(guò)下面一個(gè)問(wèn)題更令人頭痛。
屬性和方法在不在的問(wèn)題簡(jiǎn)單,可是屬性和方法變不變化的問(wèn)題可就嚴(yán)重了。在不在我們能檢測(cè),變不變呢?比如,請(qǐng)看下面的代碼:
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 />";
該代碼將產(chǎn)生如下結(jié)果:
color of tiddles is red
color of tiddles is green
請(qǐng)注意,你修改的是類(lèi)MyObject的color屬性。不過(guò)你驚奇的看到你之前實(shí)例化的對(duì)象myobj1的屬性值竟然也變化了。天!如果你的項(xiàng)目代碼是多人合作,那么,也許某個(gè)人會(huì)在編程時(shí)為了圖一己之便,擅自修改你的類(lèi)。于是,所有人的對(duì)象都變化了。于是,你們陷入了漫長(zhǎng)的debug過(guò)程中。。。。。。(不要說(shuō)我沒(méi)有告訴你啊)
上面是屬性,更有方法:
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 />";
這段代碼的結(jié)果是:
color of tiddles is red
your color of tiddles is green
哈?原來(lái)方法也能變,汗!
問(wèn)題來(lái)了。Javascript太靈活的編程方式多少讓人不適應(yīng)。如果整個(gè)Team的水平都比較高還能,沒(méi)人會(huì)犯這樣的錯(cuò)誤。不過(guò),當(dāng)有個(gè)毛頭小伙子不知情,擅自修改類(lèi),將導(dǎo)致所有的人的對(duì)象都發(fā)生變化,無(wú)論是屬性還是方法。在Javascript代碼變得越來(lái)越多的Ajax時(shí)代,這是個(gè)嚴(yán)重的問(wèn)題。
這說(shuō)明,編寫(xiě)Javascript時(shí),好的編程風(fēng)格更加重要。記得某人原來(lái)說(shuō)過(guò)這樣的話,想Java和C#這些比較嚴(yán)格的語(yǔ)言,雖然降低了靈活性,但也減少了犯錯(cuò)誤的可能。這樣,即使一個(gè)新手,他寫(xiě)出的代碼也不會(huì)和高手差太多。不過(guò),像Javascript這樣的腳本語(yǔ)言,由于太靈活,所以,高手寫(xiě)出的是天使,而新手寫(xiě)的,可能是魔鬼!