作者 Jack Herrington譯者 張凱峰 發(fā)布于 2008年11月6日 上午3時(shí)21分
我們還是勇敢面對吧:客戶(hù)端對于Java程序員來(lái)說(shuō),一直都不是個(gè)友好的地方。Java在客戶(hù)端的技術(shù),包括applet、Swing和JavaFX到目前為止只取得了有限的成績(jì)。JavaScript除了它的名字外,幾乎沒(méi)有什么地方像Java語(yǔ)言。而Adobe Flash呢,它看起來(lái)的確像JavaScript,真的嗎?也許在幾年前說(shuō)Flash就像JavaScript一樣是可以理解的,但隨著(zhù) ActionScript 3的出現,一切都改變了。而且我相信你會(huì )喜歡它的很多東西。
首先,ActionScript這門(mén)針對Adobe Flex和Flash的編程語(yǔ)言,現在是強類(lèi)型的了。它也是一流的面向對象語(yǔ)言,包括有類(lèi)和接口。它還擁有你在Java中找不到的東西——特別地,它包含屬性的get和set方法,以及一個(gè)叫做ECMAScript for XML(E4X)的語(yǔ)言擴展,可以將任何XML文檔轉換成對象,這樣你就可以通過(guò)“.”操作符直接引用它們,就跟普通對象一樣。
這篇文章會(huì )引領(lǐng)你瀏覽ActionScript的基礎內容,以及展示它與你所熟悉的Java環(huán)境的不同。到最后,你就會(huì )放棄你對ActionScript 的任何偏見(jiàn),并開(kāi)始有興趣把玩它。關(guān)于Flex、Flash和ActionScript的最偉大的事情之一就是它們完全是免費的。只要下載了Adobe Flex Builder 3就可以開(kāi)始了。Flex Builder是一個(gè)復雜的集成開(kāi)發(fā)環(huán)境(IDE),而且不是免費的,但它用于構建Flash應用的Flex軟件開(kāi)發(fā)工具包(SDK)是完全免費的。
對閱讀本文章的語(yǔ)言發(fā)燒友的一句忠告是:我并不是個(gè)語(yǔ)言教師,因此我可能忽略掉一些語(yǔ)言的細節。我也不會(huì )在這篇文章中演示ActionScript 3的所有內容。如果你的確需要這方面的內容,有很多非常棒的ActionScript 3的書(shū)籍。我能給予你的就是你對這門(mén)語(yǔ)言的初次的感覺(jué)。讓我們開(kāi)始吧。
就和Java一樣,在A(yíng)ctionScript 3中一切皆是對象。雖然有一些基本類(lèi)型,比如integer,但除了這些,一切皆是對象。類(lèi)似地,就像Java一樣,ActionScript也有命名空間和包,比如com.jherrington.animals,其表示了company/jack herrington/animal下的類(lèi)。你可以把類(lèi)放到缺省的命名空間,但更好的方法是由你自己來(lái)控制自己的命名空間。
要定義一個(gè)類(lèi),你要使用class關(guān)鍵字,這也跟Java一樣。請看示例:
package com.jherrington.animals{public class Animal{public function Animal(){}}}在這個(gè)例子中,我定義了一個(gè)Animal類(lèi),以及什么也沒(méi)干的構造函數。我還可以很容易地添加一些成員變量并完善這個(gè)構造函數,請看示例:
package com.jherrington.animals{public class Animal{public var name:String = "";private var age:int = 0;private function Animal( _name:String, _age:int = 30 ){name = _name;age = _age;}}}這里,我給一個(gè)Animal對象定義了兩個(gè)成員變量:name,一個(gè)公有的字符串,以及age,一個(gè)私有的整數。(很明顯,小動(dòng)物們對于它們的年齡都很害羞。:) )構造函數可以接受一個(gè)或兩個(gè)參數:要么是單獨的name,要么name和age。你也可以在函數聲明中為參數提供缺省的值。
你會(huì )注意到這里的類(lèi)型定義是跟Java相反的。在Java中,類(lèi)型在變量之前;而在A(yíng)ctionScript中,類(lèi)型在變量之后。這是因為強類(lèi)型定義是追加到ActionScript上的。所以為了支持舊的、沒(méi)有定義類(lèi)型的代碼,類(lèi)型就需要放在變量名的后面。
讓我添加一些方法來(lái)擴展這個(gè)示例:
package com.jherrington.animals{import flash.geom.Point;public class Animal{public var name:String = "";private var age:int = 0;private var location:Point = new Point(0,0);public function Animal( _name:String, _age:int = 30 ){name = _name;age = _age;}public function moveTo( x:int, y:int ) : void {location.x = x;location.y = y;}public function getLocation( ) : Point {return location;}}}正如你所看到的,我又添加了一個(gè)私有成員變量location,類(lèi)型是我從Flash的geometry包中引入的Point類(lèi)型。而且我還添加了兩個(gè)方法來(lái)操作location:moveTo,用來(lái)移動(dòng)animal;getLocation,用來(lái)返回當前的位置。
到目前為止,這還是以Java的方式去get和set一個(gè)值。但ActionScript方式會(huì )清晰很多,請看示例:
package com.jherrington.animals{import flash.geom.Point;public class Animal{public var name:String = "";private var age:int = 0;private var myLocation:Point = new Point(0,0);public function Animal( _name:String, _age:int = 30 ){name = _name;age = _age;}public function set location( pt:Point ) : void {myLocation = pt;}public function get location( ) : Point {return myLocation;}}}這里我使用get和set函數,它們會(huì )在客戶(hù)代碼獲取或設置成員變量location時(shí)被調用。對于客戶(hù)代碼來(lái)說(shuō),location變量看起來(lái)就像是個(gè)普通的成員變量。但事實(shí)上,你可以用你喜歡的任何代碼來(lái)響應成員變量的設值,以及處理變量的獲取。
如何來(lái)使用它呢?你可以添加一個(gè)事件,這個(gè)事件會(huì )在location發(fā)生改變時(shí)被觸發(fā)。請看示例代碼:
package com.jherrington.animals{import flash.events.Event;import flash.events.EventDispatcher;import flash.geom.Point;public class Animal extends EventDispatcher{public var name:String = "";private var age:int = 0;private var myLocation:Point = new Point(0,0);public function Animal( _name:String, _age:int = 30 )name = _name;age = _age;}public function set location ( pt:Point ) : void {myLocation = pt;dispatchEvent( new Event( Event.CHANGE ) );}public function get location( ) : Point {return myLocation;}}}現在,我指定Animal類(lèi)是一個(gè)事件分發(fā)者——也就是說(shuō),客戶(hù)代碼可以從這個(gè)對象監聽(tīng)到事件發(fā)生。接著(zhù),當location改變時(shí),我發(fā)出了一個(gè)新的事件。
下面就是客戶(hù)代碼,它創(chuàng )建了一個(gè)animal對象,并開(kāi)始監聽(tīng)事件是否發(fā)生,然后就改變了animal的location:
var a:Animal = new Animal();a.addEventListener(Event.CHANGE, function( event:Event ) : void {trace( "The animal has moved!" );} );a.location = new Point( 10, 20 );這段代碼在animal移動(dòng)時(shí)會(huì )記錄一條跟蹤信息。在A(yíng)ctionScript中,你可以定義任何類(lèi)型的消息。大多數的類(lèi)都是EventDispatcher類(lèi),你可以為它們的事件添加監聽(tīng)器。
就像Java一樣,ActionScript 3語(yǔ)言也支持接口,并使用類(lèi)來(lái)實(shí)現它們。下面的示例中,就是一個(gè)我們可以用Animal類(lèi)來(lái)實(shí)現的接口:
package com.jherrington.animals{import flash.geom.Point;public interface IAnimal{function get name() : String;function set name( n:String ) : void;function get location() : Point;function set location( pt:Point ) : void;}}在這個(gè)例子中,我為接口定義了兩個(gè)可以set和get的成員變量。沒(méi)錯,你可以在A(yíng)ctionScript接口中定義方法和成員變量。是不是很酷?
為了實(shí)現這個(gè)接口,我對Animal類(lèi)做了一點(diǎn)修改。請看示例:
package com.jherrington.animals{import flash.events.Event;import flash.events.EventDispatcher;import flash.geom.Point;public class Animal extends EventDispatcher implements IAnimal{private var myName:String = "";public function get name() : String{return myName;}public function set name( n:String ) : void{myName = n;dispatchEvent( new Event( Event.CHANGE ) );}private var myLocation:Point = new Point(0,0);public function set location ( pt:Point ) : void {myLocation = pt;dispatchEvent( new Event( Event.CHANGE ) );}public function get location( ) : Point {return myLocation;}public function Animal( _name:String ){name = _name;}}}當然,我也可以為這個(gè)類(lèi)添加特定的變量和方法,或者實(shí)現除了IAnimal接口之外的其他接口。但是和Java一樣,我只能繼承一個(gè)基類(lèi)。
靜態(tài)和常量
ActionScript 3支持常量和靜態(tài)成員變量,以及靜態(tài)方法。常量定義起來(lái)很方便,請看示例:
public const MINIMUM_AGE:int = 0;public const MAXIMUM_AGE:int = 2000;
常量可以是你期望的任何類(lèi)型,但它們必須是在編譯時(shí)定義。如果你愿意,你也可以把它們定義成受保護的或者是私有的作用域。
為了演示一下靜態(tài)方法,我在Animal類(lèi)中寫(xiě)了一個(gè)工廠(chǎng)方法:
public static function buildAnimal( n:String ) : IAnimal {return new Animal( n );}使用靜態(tài)方法的另外一種方式是單例模式。下面就是一個(gè)針對Animal類(lèi)的單例工廠(chǎng)類(lèi):
package com.jherrington.animals{public class AnimalFactory{private static var _factory:AnimalFactory = new AnimalFactory();public static function get instance() : AnimalFactory {return _factory;}public function build( n:String ) : Animal {return new Animal( n );}}}我使用該單例工廠(chǎng)的instance成員變量來(lái)獲得其對象,并調用它:
private var b:Animal = AnimalFactory.instance.build( "Russell" );
這句代碼使用單例工廠(chǎng)對象創(chuàng )建了一個(gè)新的名叫Russell的animal對象。
為了演示繼承,我寫(xiě)了三個(gè)接口和類(lèi)。第一個(gè)是之前的IAnimal接口,第二個(gè)是Animal類(lèi),第三個(gè)是名叫Dog的繼承類(lèi),它覆寫(xiě)了一個(gè)方法。
接口IAnimal定義如下:
public interface IAnimal{function get name() : String;function set name( n:String ) : void;function move( x:int, y:int ) : void;}我對它進(jìn)行了簡(jiǎn)化,這樣它只有一個(gè)name成員變量和一個(gè)move()方法。第一個(gè)實(shí)現這個(gè)接口的是Animal類(lèi):
public class Animal extends EventDispatcher implements IAnimal{private var myName:String = "";public function get name() : String{return myName;}public function set name( n:String ) : void{myName = n;dispatchEvent( new Event( Event.CHANGE ) );}public function Animal( _name:String ){name = _name;}public virtual function move( x:int, y:int ) : void{}}然后,Dog類(lèi)在Animal類(lèi)的基礎上構建起來(lái),它具有自己的構造函數,并覆寫(xiě)了move()方法:
public class Dog extends Animal{public function Dog(_name:String){super(_name);}public override function move( x:int, y:int ) : void{trace( 'Moving to '+x+', '+y );}}這看起來(lái)非常像Java代碼,所以你會(huì )感覺(jué)到用ActionScript來(lái)實(shí)現自己的面向對象設計會(huì )非常輕松。
ActionScript中的操作符和你在Java中看到的完全一樣。類(lèi)似地,算術(shù)和布爾操作符也是一樣的:
var a:int = 5;var b:int = 6;var c:int = a * b;c *= 10;var d:Boolean = ( c > 10 );var e:int = d ? 10 : 20;
這些實(shí)例演示了一些不同的操作符。在這些示例中,ActionScript和Java的唯一不同在于定義變量的語(yǔ)法不一樣。
跟操作符一樣,條件語(yǔ)句也是完全一樣的,請看示例:
if ( a > 10 ) {trace( 'low' );}else if ( a > 20 ) {trace( 'high' );}else {threw new Exception( "Strange value" );}這里演示了條件語(yǔ)句的語(yǔ)法,以及如何拋出異常。異常處理和Java中的完全一樣。你可以定義自己的異常類(lèi)型,或者直接使用標準的Exception類(lèi)。
下面是try,catch和finally語(yǔ)法的使用:
try{location = new Point( -10, 10 );}catch( Exception e ){trace( e.toString() );}finally{location = null;}這段代碼試圖設置location,并在錯誤發(fā)生時(shí)跟蹤錯誤信息。不管哪種情況,最終,location都會(huì )被設為null。
ActionScript 3沒(méi)有強類(lèi)型的容器類(lèi),但數組和哈希表使用起來(lái)還是非常容易的。這里是一個(gè)使用for循環(huán)來(lái)迭代一個(gè)數組的例子:
var values:Array = new [ 1, 2, 5 ];for( var i:int = 0; i < values.length; i++ )trace( values[i] );
但這并不是你在A(yíng)ctionScript中迭代數組應該使用的方式。最好的方式是使用for each語(yǔ)法,請看示例:
var values:Array = new [ 1, 2, 5 ];for each ( var i:int in values )trace( i );
這段代碼迭代訪(fǎng)問(wèn)數組中的每個(gè)元素,并把i的值設置為每個(gè)元素的值。
要創(chuàng )建一個(gè)哈希表,你可以使用ActionScript中基本的Object類(lèi)型:
var params:Object = { first:'Jack', last:'Herrington' };for( var key:String in params )trace( key+' = '+params[key] );ActionScript起源于JavaScript意味著(zhù)基礎對象類(lèi)型是基于插槽(slots-based)的容器,這樣你可以輕而易舉地把它作為哈希表來(lái)使用。
正則表達式是ActionScript中的基礎語(yǔ)法。比如下面這段代碼:
if ( name.search( /jack/i ) ){trace('hello jack');}是對一個(gè)字符串的簡(jiǎn)單檢查。
這段代碼是使用正則表達式來(lái)執行分割操作:
var values:String = "1,2,3";for each( var val:String in values.split(/,/) ) {trace( val );}你是否應該把正則表達式嵌在自己的核心代碼里面,是值得商榷的。Java的架構師們顯然認為這些表達式應該留在一個(gè)外部的庫中。但我認為,它們非常有用,所以它們應該像在A(yíng)ctionScript中這樣被集成。
XML應用得很廣泛,以至于A(yíng)ctionScript直接把它構建在語(yǔ)言的語(yǔ)法里面以示支持。如果你是個(gè)XML愛(ài)好者,你會(huì )非常喜歡這個(gè)的。請看示例:
var myData:XML = <names><name>Jack</name><name>Oso</name><name>Sadie</name></names>;for each ( var name:XML in myData..name ) {trace( name.toString() );}這段代碼定義了一個(gè)XML文檔,然后對它進(jìn)行搜索并打印出所有的標簽
下面這段代碼也是獲取<name>
var myData:XML = <names><name type="person">Jack</name><name type="dog">Oso</name><name type="dog">Sadie</name></names>;for each ( var name:XML in myData..name.(@type='dog') ) {trace( name.toString() );}@語(yǔ)法有點(diǎn)類(lèi)似于XPath和XSLT。它用來(lái)指定我們要查看的是屬性而不是XML元素本身。
E4X是對這門(mén)語(yǔ)言的夢(mèng)幻增強。它把XML解析從繁瑣變成了輕松愉快的事情。Web services甚至也可以以E4X的格式返回以便于解析。
Adobe對于A(yíng)ctionScript做了一些非凡的改進(jìn)。它是一門(mén)比人們想象的成熟得多的語(yǔ)言。我認為你會(huì )最終發(fā)現Adobe所做的,就是吸取了Java的得失教訓,并把它們合并進(jìn)ActionScript 3語(yǔ)言的開(kāi)發(fā)中。你會(huì )很樂(lè )意看到最后的結果。
聯(lián)系客服