對於熟悉C#和Java的兄弟們,面向對象的三大思想(封裝,繼承,多態)肯定是了解的,今天我想講講如何在Javascript中利用封裝這個特性,開講!
我們會把現實中的一些事物抽象化成一個Class並且把事物的屬性(名詞)當作Class的Property把事物的動作(動詞)當作Class的methods。在物件導向的語言中(C#等)都會有一些關鍵字來修飾類別或屬性(Private,public,protect),這些關鍵字描述了存取的權限,不多做解釋。
我們來看看Javascript的易變的特性(我們也用上一次的例子):
var Man = function (name, age) { } var Person = new Interface("Person", ["GetName", "GetAge"]); Man.prototype = { GetName: function () { return this.Name; }, } var Alan = new Man("Alan", 25); alert(Alan.GetAge()); Alan.DisplayAll = function () { return "Name: "+this.GetName() + "; Age: " + this. GetAge() } alert(Alan.DisplayAll());
我先創建了一個Class(Javascript的匿名方法)擁有2個公共的(public)的字段(這篇blog會詳細講解,繼續往下看)和2個public的方法,我們創建了一個Instance--Alan,但是我可以為這個Instance動態的添加一個DisplayAll的方法,我想任何面向對象的語言是做不到這一點的,Javascript的靈活體現之一。
我們現在假設一個場景,如果有很多的程式設計師要用這段程式碼,由於Javascript的易變性,程式設計師就可以在實例化後改變Name的值,那初始化的動作就沒有意義了:
var Alan = new Man("Alan", 25); Alan.Name = "Alice"; //悲劇了,我alert的時候變成Alice了 alert(Alan.GetName());讓外部的人去任意的修改這個字段,在Java或C#中我們只需要個這個字段改為Private,就萬事OK了,但是Javascript沒有這個關鍵字,那我們需要這麼做呢,這就是這篇blog存在的意義
我們可以想下在C#除了設定Private之外我們還可以怎麼做?我們可以設定Setter和Getter方法。
var Person = new Interface("Person", ["SetName", "SetAge", "GetName", "GetAge var function (name, age) { this.SetAge(age); this.SetName() SetName: function (name) { this.Name = name; }, SetAge: function (age) { this Alan.Age = age; }, GetName: function () { return this.Name; }, new Man("Alan", 25); Alan.Name = "Alice"; //悲劇了,我alert的時候變成Alice了 Alan.SetAge(10);//悲劇,被別人把我的年齡給這麼小 alert(Alan.GetName()); function () { return "Name: "+this.GetName() + "; Age: " + this.GetAge() } alert(Alan.DisplayAll());
我們發現似貌如C#中的似貌和Getter,但是還是可以被外部修改。但是從約束上來看,似乎比上面的code好看些,透過方法來設定初始值。但是問題還是沒有解決,我們來看看下面一種方法:閉包
//我需要解釋一下,在Javascript中是透過This關鍵字來開發權限的(Public)。
在講閉包之前,我們需要了解下閉包的本質: 在Javascript中,只有方法是有作用域的,如果在方法中聲明的變數在外部是無法訪問的,那Private的概念就出來了。
var Person = new Interface("Person", ["SetName", "SetAge", "GetName", "GetAge"]); var Man = f this.SetName = function (newname) { name = newname; } this.SetAge = function (newage) {age = newage; } this.GetAge = function () { return age; } this Alan.SetAge(newage); this.SetName(newname); 現在name是private了,我是無法去修改的 Alan .SetAge(10); //悲劇,被別人把我的年齡給這麼小 alert(Alan.GetAge());
現在私有的功能就實現了,我們只是用Var來代替了This而已。 //我們把公共(Public)並且可以訪問Private的方法稱為特權方法,例如上面的this.SetName, this.SetAge.
如果我們的公共方法不涉及到訪問Private的字段,那我們可以把他們放到Prototype中。 //好處是多個實例的時候記憶體中也只有一分拷貝
Man.prototype.DisplayAll = function () { return "Name: " + this.GetName() + "; Age: " + this.GetAge () }
哈哈~我們來看下稍微有點難度的東西:靜態變數和方法
我們都是知道靜態的東西屬於類別(Class),我們來修改下上面的程式碼:
var Person = new Interface("Person", ["SetName", "SetAge", "GetName", "GetAge","GetCount"]); var Man = (function () { ) { var name, age; this.SetName = c age) { age = newage; } this.GetName = function () { return name; } = function () { return age; } this.GetCount = function () { return count; } .SetName(newname); count++; } () { return "Name: " + this.GetName() + "; Age: " + this.GetAge() } var Alan1 = new Man("Alan", 25); 25); alert("There are "+Alan2.GetCount()+" instances of Man" );