[TOC]
實例字段一個對象中類的具象化特征。在類方法中,當前的對象被通過 關鍵字 `this` 引用。
# 函數
* * * * *
實例函數必須在類中定義,并使用如下的語法結構:
~~~
//訪問修飾符可以是public,private或者 omitted
//可選參數需要使用 ? 標記
public function fName(al : Type, ?a2 : Type) : Type
{
//...
}
~~~
第一個關鍵字是一個可選的訪問修飾符,聲明字段的可訪問性。如果是 public ,那么這個字段可以在類聲明的內部/外部調用,如果是 private或者當是 omitted,字段只能從內部訪問。
~~~
class Main {
static function main() {
var sample : RestrictAccessSample = new RestrictAccessSample();
trace(sample.publicMethod()); // works and traces “private method”
trace(sample.privateMethod());// throws a compilation error
}
}
class RestrictAccessSample {
public function new () { }
public function publicMethod() : String {
return privateMethod();
}
private function privateMethod() : String {
return “private method”;
}
}
~~~
本例中, privateMethod 只能在 SampleClass 類中的上下文中調用,而 publicMethod 總是可以訪問,只要是關聯到SampleClass 的一個實例。
有 private 的字段是必須的,在不暴露他們的應用程序接口之間傳送消息的功能。這個概念在OOP中被稱為封裝;開發者使用一個類并不需要清楚它的內部構造。
## 沒有參數
假定一個函數參數應該總是提供一個準備好使用的值是錯誤的。下面例子展示原因:
~~~
class Main
{
static function main()
{
var sample = new NullParameterSample();
trace(sample.cube(7));
trace(sample.cube(null));
}
}
class NullParameterSample
{
public function new () { }
public function cube(n : Float)
{
return n*n*n;
}
}
~~~
cube方法接受一個委托的浮點參數。如果測試 參數是 7, 結果是 343,如預期一樣。但是使用 null,可以完美運行在除了 Flash 9 以外的平臺,但是結果不同。
最好的方式避免這個矛盾,是在使用它們之前驗證函數參數,并拋出一個錯誤(錯誤處理在第 7 章介紹)或者回退到一個通用的結果。
上面的例子可以通過下面的方法糾正,以適用每個平臺:
~~~
public function cube(n : Float)
{
return if(n == null)
null;
else
n*n*n;
}
~~~
## 可選參數
每個函數參數都可以使用一個可選的 問號 ? 標記前綴。如果存在,表示這個參數是可選的,可以在函數調用時忽略。雖然可選參數在函數聲明的任何部分放置,但是通常好的實踐是堆在后面。
~~~
class Main
{
static function main()
{
var sample = new OptionalParameterSample();
trace(sample.quote(“quotation”, “ - “));
trace(sample.quote(“quotation”));
}
}
class OptionalParameterSample
{
public function new () { }
public function quote(text : String, ?quotesSymbol : String) : String
{
if(quotesSymbol == null)
quotesSymbol = ‘”’;
return quotesSymbol + text + quotesSymbol;
}
}
~~~
第二個參數是可選的, 當函數調用時沒有傳入第二個參數,它的值會是默認的 null ,實踐中,這樣寫:
~~~
sample.quote(“quotation”);
~~~
準確的說,應該是下面的寫法:
~~~
sample.quote(“quotation”, null);
~~~
為此,在 quote 函數中, quoteSymbol 的值會被測試,如果是 null ,一個替代默認值被分配。牢記Haxe 中變量的類型,即使是數值類型,也可以假設值 null ;因此經常謹慎的測試一個參數實際上是不是 null,否則可能引起錯誤。當希望強制某個參數可以假設為一個 null ,最好使其成為可選參數。Flash 9 有一個稍有不同的行為關于讀取 null 。12章將會深入介紹。
可選參數是獨立的:當多余一個在一行聲明的時候,可以為最后的參數設置一個值,而不用為前一個設置,盡管這可能比較混亂。思考下面的例子:
~~~
function foo(?a : String, ?b : Int, ?c : Person)
{
// body goes here
}
~~~
所有跟隨的語句都是正確的,正確的分配到相應的參數;沒有顯式聲明的參數設置為null:
~~~
foo(1);
foo(“John”);
foo(“John”, 1, person);
// where person is an instance of Person
foo(person);
~~~
但是下面的語句不會編譯:
~~~
foo(person, “John”); // wrong sequence
~~~
# 變量
* * * * *
類實例變量的聲明如下:
~~~
private var name : Type;
//訪問修飾符可以是 public, private、 和omitted
~~~
訪問修飾符目前和實例函數應用的一致。
和局部變量跟靜態變量相對的是,它不能在聲明的時候設置實例變量的值;值只能通過內部的函數調用來改變。
實例變量可以在內部函數中引用,只需要使用變量名即可,或者帶上前綴 this 。this 標識符是強制在一個函數中使用來應對沖突的名稱。
# 標識符優先級
* * * * *
當命名變量和函數時,重要的是意識到如何解析他們的標識符。對于變量和函數分配到變量,優先級優先順序從高到低,依次是:
* 局部變量
* 實例變量
* 靜態變量
* 作用于內聲明的枚舉構造器
函數的優先級如下:
* 局部變量中保存的函數
* 實例函數
* 靜態函數
如果有多個局部變量或者函數,有相同的名稱,最后聲明的將被采用。重新聲明一個局部變量或者函數并不是一個好的實踐。
實例類變量和函數可以來自當前類或者一個父級類,將在繼承章節解釋。注意函數可以被重載,而變量不行。
s 枚舉的作用于是當前的文件或者每個導入的包;這個參數在第6章部分介紹。
最終,可以有一個靜態字段是實例字段來分享他們的名字,但是不能使用類變量來通過一個類函數分享名字。
# 構造器
* * * * *
每個類可以被實例化只要它 有一個構造器,這是一個特殊的函數,每次一個新的實例創建時都會被調用。構造器的語法幾乎和實例函數的相同,除了它的名字被強制定義為 new 。函數的返回類型總是 Void,可以顯示標識或者忽略(omitted)。
因為實例變量不能再聲明的位置初始化,構造器可以用于這個目的。
要改進 BlogEntry 類,一個包含常見數據的變量被添加,它的值在實例化時自動生成。
~~~
class BlogEntry
{
public var title : String;
public var content : String;
public var createdOn : Date;
public function new ()
{
createdOn = Date.now();
}
}
~~~
構造器,包括其他任何函數,都可以使用參數,在 Blog例子中可以用來設置一些BlogEntry聲明的限制,并減少創建一個類可用實例的代碼行數。
~~~
class BlogEntry
{
public var title : String;
public var content : String;
public var createdOn : Date;
public function new (title : String, content : String)
{
this.title = title;
this.content = content;
createdOn = Date.now();
}
}
~~~
實例以這個方式創建:
~~~
class Main
{
static function main()
{
var entry : BlogEntry = new BlogEntry(“My First Blog Entry”, “...”); trace(entry.title);
}
}
~~~
通常當一個 blog entry被創建,它只是一個草稿,沒有真的準備去發布。最好有一個 publish() 方法,在一個請求準備好上線之后來確定狀態,和一個 unpublish() 方法,在必要的時候取消發布。
~~~
class BlogEntry
{
public var title(default,default) : String;
public var content(default,default) : String;
public var createdOn : Date;
public var onlineInfo(getOnlineInfo,null) : String;
private var publishedOn : Date;
public function new (title : String, content : String)
{
this.title = title;
this.content = content;
createdOn = Date.now();
publishedOn = null;
}
public function publish() : Void
{
publishedOn = Date.now();
}
public function unpublish() : Void
{
publishedOn = null;
}
public function isOnline() : Bool
{
return publishedOn != null
&& publishedOn.getTime() < = Date.now().getTime();
}
private function getOnlineInfo() : String
{
if(publishedOn == null)
return “Not yet on-line”;
else
{
// getTime() returns the time in milliseconds since 1970-01-01
// we have to divide the time span by 24 hours=24*60*60*1000=86400000
var daysOnline = (Date.now().getTime()-publishedOn.getTime())/86400000;
return if(daysOnline < 1)
“Published Today”;
else if(daysOnline < 2)
“Published Yesterday”;
else if(daysOnline < 7)
“Published “ + Math.floor(daysOnline) + “ days ago”;
else
“Published on “ + DateTools.format(publishedOn, “%Y-%m-%d”);
}
}
}
~~~
當私有變量 publishedOn 設置為 null ,記錄尚未準備好發布,只是一個草稿,使用了 publish() 方法,設置值為當前的日期,因此,準備好被顯示了。方法 isOnline() 用來檢查是否記錄已經被發布,而 getOnlineInfo() 返回信息,以一個易讀的格式,在自發布后到現在消逝的時間。
# 變量修飾符
* * * * *
類變量支持使用修飾符,或者屬性,允許修改它們的標準行為:
對變量值的訪問可以限制為只讀或者只寫。
一個 getter 和/或 一個 setter 方法可以聲明來訪問變量的值。
變量修飾符的一種語法如下:
~~~
private var name(getModifier, setModifier) : Type;
~~~
訪問修飾符和在函數中解釋的有相同的行為。type 是屬性可以管理的一個類型。
getModifier 和setModifier 可以假設如下描述的一個值:
|變量值修飾符|描述|
| -- | -- |
|null|訪問被禁止。用在 getKeyword 位置,它表示變量只允許寫;使用它在 setKeyword 表示渲染變量只讀。即使沒有錯誤報告,這兩個位置用 null 是沒有意義的。|
|default|變量被視為傳統變量。在 getKeyword 和 setKeyword 位置通過 default 聲明,和一個實例變量完全相同,但是可以強制語義訪問修飾符在未來可能需要改變。|
|方法名|指定的方法,通常標記為私有,必須術語和屬性的類相同的,用來訪問屬性值。如果在 getKeyword設置會是一個 getter,否則則是 setter 。|
|dynamic|通過一個運行時生成的方法提供訪問|
關聯了只讀/只寫 屬性的變量在擁有它的類內部具有完全的訪問性。只有在外部才具有訪問限制,并且只對公共變量有意義。
一個 getter 方法必須符合簽名 Void->T, 意味著方法必須接受沒有參數并且必須返回一個 T 類型的值,T 是變量的類型。 setter方法的簽名是 T->T, 意味著函數必須接收和返回一個和屬性本身類型相同的值。
setter 方法,雖然它用來改變一些對象實例內部的內容,必須始終返回一個值(通常連續訪問getter方法返回的同樣的)。需要的許可語法如下:
~~~
var v = c.step++;
~~~
step是一個通過這種方式定義的屬性:
~~~
public var step(getStep,setStep) : Int;
private function getStep() : Int
{
return counter;
}
private function setStep(value : Int) : Int
{
counter += 1;
return counter;
}
~~~
如果 setStep 不返回一個值, v 會設置為 Void ,這和期待的邏輯相反。
這個修飾符允許限制從類外部對變量的訪問,方便的用于 blog entry 的例子來強制 createdOn 變量為只讀,所以它的值在創建時被設置,不能在以后被偽造。
~~~
public var createdOn(default,null) : Date;
~~~
嘗試訪問 craetedOn 屬性,如果值被讀取可以正常執行,但是賦值則會報告一個錯誤。
~~~
class Main
{
static function main()
{
var entry : BlogEntry = new BlogEntry(“My First Entry”, “...”);
trace(entry.createdOn); // works
entry.createdOn = Date.now(); // fails
}
}
~~~
要展示另一個只讀訪問的使用,改變例子為介紹一個新的變量 excerpt ,它包括一個小的關于blog entry的描述,使用了 content 屬性前面一部分單詞。在每次調用時值都被計算,所以類不需要任何支持的變量。
~~~
public var excerpt(getExcerpt, null) : String;
private function getExcerpt() : String
{
return content.substr(0, 10) + “ ...”;
}
~~~
新的代碼可以這樣使用:
~~~
class Main
{
static function main()
{
var entry : BlogEntry = new BlogEntry( “My First Entry”,“Using the BlogEntry class is easy.”);
trace(entry.excerpt);
}
}
~~~
excerpt 變量現在會輸出 content 變量的前十個字符跟隨一個空格和一個省略號。某些情況下最好提供一個替代文本,而不是盲目裁剪blog entry 的content。要獲得這個,一個 setter 方法和一個新的 private 變量 definedExcerpt 被添加到類。getter 方法也被修改來使用新定義的變量,如果它不同于 null 或者反復用于裁剪功能。
~~~
private var definedExcerpt : String;
public var excerpt(getExcerpt, setExcerpt) : String;
private function setExcerpt(value : String) : String
{
definedExcerpt = value;
return definedExcerpt;
}
private function getExcerpt() : String
{
return if(definedExcerpt != null)
definedExcerpt;
else
content.substr(0, 10) + “ ...”;
}
~~~
excerpt 屬性現在可以設置為一個新的值。
~~~
entry.excerpt = “Blog Entry is easy”
~~~
在傳統的OOP中,getter 和 setter 方法是首選的方式訪問變量,但是在 動態語言中,例如 JavaScript,有一個普遍的技巧來忽略這個實踐而是使用一個更短的容易的來讀代碼和更快的執行,通過屬性定義你可以總是切換實例變量為訪問方法。
dynamic 關鍵字在變量的上下文中是一個高級特性。要訪問一個標記為dynamic的屬性的值,必須在運行時提供訪問方法。應用本身必須動態提供一個get/set的實現。這可以通過在運行時修改一個實例或者類的屬性來實現,使用Haxe的反射機制。
屬性通過下面方式定義:
~~~
var runtime(dynamic,dynamic) : String;
~~~
兩種放問題必須被動態提供,必須命名為 get_runtime 和 set_runtime(后綴get/set_ 跟隨屬性名),如下例子所示:
~~~
Reflect.setField(objectInstance, “get_runtime”, function()
{
// do something here and return a string return “”;
});
Reflect.setField(objectInstance, “set_runtime”, function(value)
{ // do something here and return a string return value;
});
~~~
在實踐中編譯器不會檢查get_X 和 set_X的實際存在方法,因此它們可以被提供到運行時。
objectInstance 是一個對象的引用,實現定義runtime屬性的類。
- 本書目錄
- 第一章:Haxe介紹
- 互聯網開發的一個問題
- Haxe是什么,為什么產生
- Haxe編譯工具
- Haxe語言
- Haxe如何工作
- 那么Neko是什么
- Haxe和Neko的必須條件
- 本章摘要
- 第二章:安裝、使用Haxe和Neko
- 安裝Haxe
- 使用Haxe安裝程序
- 在Windows上手動安裝Haxe
- Linux上手動安裝Haxe
- 安裝Neko
- Windows上手動安裝Neko
- 在Linux上安裝Neko
- Hello world! 一式三份
- 編譯你的第一個Haxe應用
- 你的程序如何編譯
- HXML編譯文件
- 編譯到Neko
- 編譯為JavaScript
- 程序結構
- 編譯工具開關
- 本章摘要
- 第三章:基礎知識學習
- Haxe層級結構
- 標準數據類型
- 變量
- 類型推斷
- 常數變量
- 簡單的值類型
- 浮點類型
- 整型
- 選擇數值類型
- 布爾類型
- 字符串類型
- 抽象類型
- Void 和 Null
- 動態類型
- unknown類型
- 使用untyped繞過靜態類型
- 注釋代碼
- 轉換數據類型
- Haxe數組
- Array
- List
- Map
- Haxe中使用日期時間
- 創建一個時間對象
- Date組件
- DateTools類
- 操作數據
- 操作符
- Math類
- 使用String函數
- 本章摘要
- 第四章:信息流控制
- 數據存放之外
- 條件語句
- if語句
- switch語句
- 從條件語句返回值
- 循環
- while循環
- for循環
- 循環集合
- Break和Continue
- 函數
- 類的函數
- 局部函數
- Lambda類
- 本章摘要
- 第五章:深入面向對象編程
- 類和對象
- 實例字段
- 靜態字段
- 理解繼承
- Super
- 函數重載
- 構造器重載
- toString()
- 抽象類和抽象方法
- 靜態字段,實例變量和繼承
- 繼承規則
- 使用接口
- 高級類和對象特性
- 類的實現
- 類型參數
- 匿名對象
- 實現動態
- Typedef
- 擴展
- 枚舉
- 構造器參數
- 本章摘要
- 第六章:組織你的代碼
- 編寫可重用代碼
- 使用包
- 聲明一個包
- 隱式導入
- 顯式導入
- 枚舉和包
- 類型查找順序
- 導入一個完整的包
- 導入庫
- Haxe標準庫
- Haxelib庫
- 其他項目中的庫
- 外部庫
- 使用資源
- 文檔化代碼
- 離線文檔
- 在線文檔
- 單元測試
- haxe.unit包
- 編寫測試
- 本章摘要
- 第七章:錯誤調試
- trace函數
- trace輸出
- haxe的trace和ActionScript的trace
- 異常
- 異常處理
- CallStack和ExceptionStack
- 異常管理類
- 創建完全的異常處理類
- 異常類代碼
- 本章摘要
- 第八章:跨平臺工具
- XML
- XML剖析
- Haxe XML API
- 正則表達式
- EReg類
- 模式
- 定時器
- 延遲動作
- 隊列動作
- MD5
- 本章摘要
- 第九章:使用Haxe構建網站
- Web開發介紹
- Web 服務器
- 使用Web服務器發布內容
- HTML速成課程
- Haxe和HTML的區別
- NekoTools Web Server
- Apache安裝mod_neko
- Windows安裝Apache和mod_neko
- Linux安裝Apache和Mod_Neko
- 第一個Haxe網站
- 使用Neko作為網頁Controller
- neko.Web類
- Neko作為前端控制器
- 本章摘要
- 第十章:使用模板進行分離式設計
- 什么是模板
- Template類
- Template語法
- 使用資產
- 何時在模板中使用代碼
- 服務器端模板的Templo
- 安裝Templo
- 使用Templo
- haxe.Template和mtwin.Templo表達式上的區別
- Attr表達式
- Raw表達式
- 邏輯表達式
- 循環表達式
- set, fill, 和 use表達式
- Templo中使用宏
- 手動編譯模版
- 第十一章:執行服務端技巧
- 第十二章:使用Flash構建交互內容
- 第十三章:使用IDE
- 第十四章:通過JavaScript制作更多交互內容
- 第十五章:通過Haxe遠程通信連接所學
- 第十六章:Haxe高級話題
- 第十七章:Neko開發桌面應用
- 第十八章:用SWHX開發桌面Flash
- 第十九章:多媒體和Neko
- 第二十章:使用C/C++擴展Haxe
- 附加部分