function在javascript中用來建立函數或方法,但要想實現物件導向方式的編程,類是不可或缺的角色之一,而且是主角。但javascript中並沒有類概念,所謂的類也是類比而來,通過函數加閉包類比出類成員及私人成員(關於閉包可以參見跨越邊界: 閉包)。這裡我們將用比較平實的方式來瞭解一下javascript中的”類”,避開一些生硬的原理。
既然是用function來類比類,所以編寫代碼建立類的關鍵字還是function。我們建立一個座標點類。
function Point() {
this.X = 0;
this.Y = 0;
};
var zeroPoint = new Point();
alert("當前座標值( X:" + zeroPoint.X + " , Y:" + zeroPoint.Y + " )");
大家都知道非靜態類成員的訪問需要通過對象來完成,所以先new出了一個Point類型對象,再通過該對象完成X和Y軸座標值的訪問。從文法上來說,javascript類對象的建立過程和C#等差不多,但實現機制卻不相同。這裡的new建立出了一個Object,後續的Point()函數執行時將其this指向了這個新的Object對象。Point中的this.X和this.Y是Point類的兩個公用成員,所以Point的對象可以直接對它們進行訪問。
說到類成員或對象的成員,免不了要提到可訪問性的問題。在javascript的類中,也有public成員和private成員之分,但究其細節卻不盡相同。javascript私人成員也是些在類外部不可以通過對象進行操作的成員,其實在類的內部成員之間私人成員也不定能被訪問。在類的內部一般只有私人成員和私人成員之間可以互相的訪問,你可以認為其它成員許可權不夠不能操作這些隱私的東西,但如果你有特權,那就不一樣了,管它私人公開照用不誤。私人成員變數和普通變數聲明一樣,用var關鍵字,私人方法可以用var聲明變數來接收方法對象,也可以像普通方法那樣去構建。
function Lady() {
var age = 30;
var name = "菜花";
var think = function() {
alert("其實我今年" + age + "歲。");
};
function fancy(){
alert("幻想變成20歲。");
};
this.Introduce = function() {
alert("我叫" + name + " , 今年20歲。");
};
};
var younglady = new Lady();
alert(younglady.age);//結果undefined
younglady.think(); //不支援
younglady.fancy(); //不支援
上面是一個Lady類,age、think、fancy都是私人成員,think和fancy方法可以訪問age和name,think和fancy兩個方法也可以互相進行調用。但它們是私人的,所以建立出來的youngLady對象並不能調用到age、think和fancy,當然也不能調用到name。如果私人成員只能互相之間調用,其實也就失去了私人成員存在的意義。javascript提供特權成員可以建立外界和私人成員互連的橋樑。特權成員是公用成員的一種,公用成員有普通公用成員、特權成員和對象公用成員。
特權成員就是在類中用this.XX的方式建立的成員,它們可以通過對象來被調用,它們也可以訪問私人成員,可以建立私人成員被訪問的通道。
function Lady() {
var age = 30;
this.Name = "菜花";
var think = function() {
alert("其實我今年" + age + "歲。");
};
function fancy() {
alert("幻想變成20歲。");
};
this.Introduce = function() {
alert("我叫" + this.Name + " , 今年" + age + "歲。");
};
};
var younglady = new Lady();
younglady.Introduce(); //Introduce
普通公用成員的建立,不在類的裡面來編碼,而是通過類的prototype來建立。添加普通公用成員都直接添加到類的prototype中,而prototype就是一個像JSON對象一樣的成員集對象。當我們進行對象建立時,可以認為會將類prototype中的成員整體copy入新的Object對象中。
var younglady = new Lady();
younglady.Introduce(); //Introduce
Lady.prototype.Hobby = "上網";
Lady.prototype.GetName = function() {
return this.Name;
};
var lady2 = new Lady();
alert(lady2.GetName());
alert(lady2.Hobby);
上面代碼通過prototype為Lady類添加了普通公用成員GetName方法和Hobby屬性,因為是公用成員,所以它們可以和原先定意在類中的特權成員進行互相訪問。因為公用成員可以互相訪問。對上述代碼做些修改。如下。
var younglady = new Lady();
Lady.prototype.Hobby = "上網";
Lady.prototype.GetName = function() {
return this.Name;
};
alert(younglady.GetName());
alert(younglady.Hobby);
先建立出Lady對象,再修改類成員,先前建立好的對象也具有了新的成員。這就是prototype做為類原型所帶來的好處,這裡簡單理解,可以認為prototype是類對象的模版,模版的修改會影響到所有該類對象。
在添加普通成員的時候也可以來個批量的添加,直接用一個新的JSON對象來賦給prototype就可以了。但是要注意,現在是將原先的prototype進行了替換,在替換之前建立的對象引用的是舊的prototype對象,所以對prototype替換之前建立的對象不會有Hobby和GetName成員。
Lady.prototype = {
Hobby: "上網",
GetName: function() {
return this.Name;
}
};
var younglady = new Lady();
alert(younglady.GetName());
alert(younglady.Hobby);
除了在構建類時可以添加公用成員,還可以對對象直接進行成員操作。這在本小系列第二篇文章裡有描述。這裡做一下補充,對對象直接添加的成員,也是一種公用成員,這些成員也可以和類中原先具有的公用成員進行訪問。
younglady.SetName = function(name) {
this.Name = name;
};
younglady.SetName("菜明");
alert(younglady.GetName());
以上說了一下類成員的東西,下次再說說類繼承相關的東西。(如有不當說法請指正)
javascript"物件導向編程" - 1 萬物皆對象
javascript"物件導向編程" - 2 聊聊對象的事
javascript"物件導向編程" - 3 function是方法(函數)