看以下這段代碼:
<html>
<body>
<script>
class1 = function()
{
// 私人屬性
var m_first = 1;
var m_second = 2;
// 私人方法
function method1()
{
alert(m_first);
}
var method2 = function()
{
alert(m_second);
}
// 構建函數
{
method1();
method2();
}
}
var o = new class1();
// 提示未定義
alert(o.m_first);
// 錯誤:對象不支援此屬性或方法
o.method1();
</script>
</body>
</html>
這段代碼其實是在介紹JavaScript如何建立一個私人變數與私人方法。這個不是大問題。要關注的是,進入類後,類的私人方法就可以使用類的私人變數了,一層層的,有意思。而類的私人方法使用全域變數也是正常,沒有懸念。類的公用方法使用類的私人變數或全域變數亦沒有問題。
var i=2;
……
this.method3=function () //類的公用方法
{
alert (m_first + ":" + i); //使用類的私人變數與全域變數
}
……
這裡有列出兩種構建私人函數的方法(常規函數定義與匿名函數賦給變數),事實上還會有更多,只要構建函數的方法都可以拿來一試,如:new Function
但為什麼會“第二種方式更靈活一些”?
如果全域變數與私人變數重名怎麼辦?這個問題好象很變態,如果我是主管的話,會把這種程式員拿來罵一頓,(編程的命名體系也要檢討一下)。只當學術研究,實際走一下,還真的不好研究:
var m_first=1;
class1 = function()
{
var m_first = 2;
function method1()
{
var m_first=3;
alert(window.m_first + "?" + this.m_first + "?" + m_first + "?" +
method1.caller.m_first);
想把1?2?3顯示出來,就是搞不定。
構建函數,該段代碼把除聲明變數、定義函數的語句之外的執行語句用 { } 括起來,“這樣做雖然沒有必要,但是代碼看上去更加清晰。”,認同!以前認為是雜亂無章的代碼,現在有一個這麼時髦的名稱,那當然高興啊。
這裡,原作者有提醒一點,建構函式應該放在整個類定義的最後部分,因為那時,該定義的函數都定義好了,或該賦初值的變數也賦好了(變數的定義在任何地方都可以)。這裡又有個問題:如果函數是用普通的直接定義,其實建構函式放哪都一樣,如果函數是用匿名函數賦給變數的方式定義,則就要執行過才行。在VS的單步跟蹤時,你就會發現,如果是語句:
var m_first = 1;
調試器會走過,而如果是語句:
var m_first;
則調試器就不會理會。同樣,如果是語句:
var method2 = function () { ... }
調試器會走過(一下子整段走過,而不是具體執行其中的代碼),如果是語句:
function method1() { ... }
調試器也不理會。從這一點來看,我就覺得var method2=function() { ... }的這種定義方法並不好。調試時還要走過這句話。
因此,如果你的代碼都是定義型的語句,那構建函數其實是可以放在類首的,而且我也覺得這樣更好。
此外作者為了避免在構建函數中建立多餘的私人變數,建議把構建函數單獨划出一個普通函數來,這個建議也不錯,如下代碼就很容易造成誤解
<html>
<body>
<script>
var i=1;
class1 = function()
{
// constructor
{
for (var i=0; i<5; i++)
{
document.write("OK");
}
method1();
}
function method1()
{
alert(i); //最後提示什麼,全域變數1還是局部變數5?答案是:5
}
}
var o = new class1();
</script>
</body>
</html>
不過函數的名稱,我想用constructor會不會造成誤解?因為constructor已經有意義的了。並且它太長了一點。
<html>
<body>
<script>
class1 = function()
{
function constructor()
{
document.write("OK");
}
constructor();
function method1()
{
alert("TT");
}
}
var o = new class1();
alert(o.constructor); //這裡會不會造成誤解
</script>
</body>
</html>
所以我想用_cs固定作為構建函數。本也有想用類名,但那更容易誤解,而_+類名作為構建函數,則會因為類改名(不穩定階段,我經常這樣幹),構建函數也要跟著改名。_cs可以理解為ConStructor,也可以理解為Class Start,會打cs的人更不會忘,前面加一個底線更顯示它的特殊性。好,就這樣。
開始隨想,我們在C#中使用的類與其執行個體,是不是也是像這樣,構建一個執行個體其實是讓程式有一個機會去執行一遍類的相關代碼。
第二個,這段代碼的作者也有個習慣,私人變數用m_來開頭,而VB6中的產生控制項嚮導也是這個習慣,因此也變成我的習慣了。
第三個,提示類的私人變數,系統其實不會嚴重錯誤而中止,而是提示“undefined”,而執行一個私人方法,系統就會嚴重出錯。顯然前者與我們普通的編程有衝突,也隱藏著潛在的問題(難怪我的JavaScript程式錯誤那麼多),如果有一種方法保證如果使用私人變數,系統也會彈出嚴重錯誤就好了(當然,更好的是,在沒有執行前就告訴你這些地方嚴重錯誤)。
最後,作者提示了一個最後,class1是用匿名函數的方式來定義的,沒有帶var,說明它是
一個全域類,我不太想用匿名函數,因此改為普通函數來定義。這時,我才發現用普通函數定義的,與匿名函數賦給變數的區別點之一:後者可以讓函數為全域函數(但再想一下,這不一定是件好事)。
天啊,這段代碼我寫了這麼多,始料未及(?)