Flash ActionScript3 殿堂之路第四章--4.4 *函数高级使用技巧
2010-09-23 16:11
381 查看
4.4 *函数高级使用技巧
知道函数本身也是一种对象,会给我带来极大的便利和编程思维的改变。下面共享几个笔者使用的技巧。
4.4.1技巧一:代理函数对象
这是最简单的运用。设立一个代理函数对象,根据条件的不同,将它指向不同的函数,可实现动态改变(即运行时改变)。相信有经验的程序员都了解动态改变函数的便利性。而且在于ActionScript提供了这种便利,运用这个特性可以衍生大量技巧。见示例4-4。
var kingdaFunc:Function;
var sex:String = “male”;
if (sex == “male”) {
kingdaFunc = maleFunc;
} else {
kingdaFunc = famaleFunc;
}
kingdaFunc();
//输出:I am a boy
function maleFunc() {
trace (“I am a boy”);
}
function femaleFunc() {
trace (“I am a girl”);
}
复制代码
4.4.2技巧二:建立函数执行队列
比如说,我有一个对象,我想根据不同的情况对它进行一系列的操作。但是有时需要所有的操作,有时有只需要一部分的操作。那么这个较高级的技巧,就能保证代码的高度重用性和简捷。见示例4-5。
示例4-5 建立函数执行队列
var funcAry:Array = new Array();
//将需要的操作步骤加入队列
funcAry.push(aFunc);
funcAry.push(bFunc);
funcAry.push(cFunc);
//供操作的对象
var originObject:Object = new Object();
//需要执行几步由execQueue这个参数决定,在实际工程运用中这个数可能是动态决定的
var execQueue:Number = funcAry.length;
//核心步骤:函数队列执行。实际运用中可以把它包装成一个函数,或者一个类的实例
for (var i:Number =0; i<funcAry.length; i++) {
funcAry (originObject);
}
//trace出执行操作后的originObject里面的内容
for (var j in originObject) {
trace (j + “:” + originObject[j]);
}
//操作步骤a,b,c
function aFunc(eO:Object) {
e0.aFuncExected = true;
trace (“aFunc()”);
}
function bFunc(eO:Object) {
eO.aFuncExected = true;
trace (“bFunc()”);
}
function bFunc(eO:Object) {
eO.aFuncExected = true;
trace (“cFunc()”);
}
复制代码
输出内容为:
aFunc()
bFunc()
cFunc()
aFuncExected:true
bFuncExected:true
cFuncExected:true
复制代码
前3行表明a、b、c3个函数按顺序执行了。后3行表明orginObject确定经过了3步操作,多了3个为true的属性。
笔者提醒:技巧可以再延伸!可以通过一个函数来管理队列里面各个元素的位置,达到改变操作函数的顺序。比如,通过一个数组来安排调用顺序。以下代码,紧接着上文的代码例子。
var operationAry:Array = [2,1,0];
for (var k:Number = 0; k<operationAry.length;k++) {
funcAry[operationAry[k]](originObject);
}
/*输出:
cFunc()
bFunc()
aFunc()
*/
复制代码
这样函数就通过2、1、0这样的倒序来执行操作。
这个技巧还有很多可以延伸的地方,比如说动态控制操作函数的参数多等,甚至可以通过外部数据(如XML)运行时改变函数执行顺序。大家可以自己研究扩展。
4.4.3技巧三:利用函数返回
函数有一个proxyObject对象,我们希望根据proxy对象的内容来确定一个方法,处理myObject对象。
当proxyObject是字符串时,我们又希望根据字符串的内容来确定返回不同的函数(或方法)。这些函数参数和类型是不完全相同的。有的可能是一个参数,有的可能是多个参数,不同类型。
那么传统的解决方法——在函数内部调用其他函数——就显得力不从心。即使解决,也不如笔者下面这个chooseFuncBy()函数简捷。缺点当然有,那就是比较灵活,使用者一定要清楚地管理好每个目标函数和判断逻辑。因为这种灵活的编程方式编译器无法检查,是不能查出类型不匹配这种错误的。初学者慎用。见示例4-6。
示例4-6 利用函数返回函数
//通过A调用只有一个参数的aFunc();
chooseFuncBy (“A”) (“A func has only one parameter.”);
//输出:aFunc(): A func has only one parameter.
//通过B调用有两个参数的bFunc();
chooseFuncBy(“B”) (“B func has two parameters.”,”No.2 parameter”);
//输出:bFunc():B func has two parameters.one more Parameter:No.2 parameter
//字符串不符,默认函数
chooseFuncBy(“wu lala”)(“I choose A function”);
//输出:Welcome to Kingda.org!My blog
var withObj:Object = new Object();
var myObj:Object =
{name:”黑羽”,blog:”http://www.kingda.org”, hobby:”Starcraft”};
chooseFuncBy(withObj)(myObj);
/*输出:
objectFunc();
name:黑羽
blog:http://www.kingda.org
hobby:Strarcraft
*/
function chooseFuncBy(input:*):Function {
//运用一:利用参数的种类来确定返回的函数
if (!(input is String)) {
return objectFunc;
}
//运用二:根据参数内容来返回函数
switch (input) {
case “A”:
return aFunc;
case “B”:
return bFunc;
default:
return kingdaFunc;
}
//…更多延伸运用:利用参数个数、is确定不同Class的实例来选择函数,等等
}
复制代码
function aFunc(nS:String) :void {
trace (“aFunc():” + nS);
}
function bFunc(nS:String, nP:String) :void {
trace (“bFunc():” + nS + “one more Parameter:”+ nP);
}
function kingdaFunc(…rest) :void {
trace (“Welcome to Kingda.org! My blog”);
}
function objectFunc(kingdaObj:Object) :void {
trace (“objectFunc():”);
for (var i in kingdaObj) {
trace (i + “:” + kingdaObj);
}
}
复制代码
4.4.4技巧四:函数动态添加实例属性
如4.3节所说,使用函数表达式定义的函数也是一个动态类对象。因此,使用函数表达式定义的函数可以动态添加属性和方法。
注意,技巧四和技巧五完全可以用面向对象的方法来解决。从面向对象的角度来说,频繁使用技巧四和技巧五不是一个好的编程习惯。虽然很方便,但由于动态属性的使用使得编译器无法进行类型检查,也使得在复杂代码中的犯错可能性增加,查错难度增大。技巧四和技巧五只是运用在一些特殊的场合,在面向过程的编程中使用稍多一些。
下面来介绍技巧的运用。
例如,利用函数动态属性来计算函数调用次数。当然,你完全可以用这个技巧来干更多更有用的事,笔者只是抛砖引玉做个小例子。
一个游戏中有开火函数shot()。我想知道总共开火了多少次,那么可以添加一个shot函数的动态属性times。注意,引用shot函数动态属性时,只能使用“函数名+数组访问符+属性名”来访问,例:shot[‘times’]。见示例4-7。
示例4-7函数动态添加实例属性
var shot:Function = function ():void {
shot[‘times’] ++;
trace (“Shot():times:”+ shot[‘times’]);
//.. 可以写些其他代码放在这儿
}
shot[‘times’] = 0;
//初始化times
shot();
//输出:Shot():times:1
shot();
//输出:Shot():times:2
shot();
//输出:Shot():times:3
复制代码
4.4.5技巧五:函数对象动态添加实例方法
技巧五就是添加方法了,更有趣一些。函数这么一摆弄之后,函数对象成了“二不像”:不像普通类实例,也不像一个函数。这个技巧可以让我们的函数变得很强大,也会让它更复杂更难以管理。本技巧即使在面向过程编程中,也只建议在小范围内少了运用,不赞成大范围大规模地使用。
见示例4-8,本例中一旦发现shot()函数开火超过3次,就会自动调reload,将开火次数重置为0。
示例4-8 函数对象动态加实例方法
var shot:Function = function():void {
shot[‘times’] ++;
trace (“Shot():times:”+ shot[‘times’]);
shot[‘reload’]();
//shot的其他代码放在这儿
}
shot[‘times’] = 0;
shot[‘reload’] = function () {
trace (“reload:”+ this[‘times’]);
if (this[‘times’] >3) {
this[‘times’] = 0;
}
}
shot[‘reload’]();
shot();
shot();
shot();
shot();
复制代码
shot();
shot();
/*输出:
reload:0
Shot():times:1
reload:1
Shot():times:2
reload:2
Shot():times:3
reload:3
Shot():times:4
reload:4
Shot():times:1
reload:1
Shot():times:2
reload:2
*/
复制代码
写在篇尾的话:可以看出,运用动态添加属性和方法的技巧,可以使Function这个特殊的东西异常强大。而且其灵活程度更是空前,试想如果动态添加的方法返回函数(见4.4.1节第一个技巧)。不要忘了,动态添加的方法可直接访问函数的输入参数,那么其衍生的技巧又有多少种呢?函数又可以变成怎样一种强有力的编程对象呢?只有想不到,没有做不到。这就是Function给我们展示的无穷灵活性。
但是,还是要说的是,技巧终归是技巧,它有其两面性。灵活是它的优点,也是它的缺点。小范围地运用让你爽快无比;大项目中大范围地使用,除非管理得很好,不然会让你头疼欲裂死而后快。
4.5 本章小结函数是面向过程编程的核心元素,也是遥望面向对象编程殿堂的第一个界碑。其重要性不言而喻。
本章讲解了ActionScript3中函数的两种定义法方法:语句定义法和表达式定义法,并花大篇幅详细地说明了二者的不同。并在函数本质一节中,点出了二者在底层实现上的不同。本章还介绍了ActionScript3中新增的函数特色、默认参数和…(rest)关键字。
在函数高级使用技巧中,介绍了ActionScript3函数特有的使用技巧。我们会发现随着不断挖掘函数自身的潜力,在慢慢地开始向面向对象思想靠拢。
知道函数本身也是一种对象,会给我带来极大的便利和编程思维的改变。下面共享几个笔者使用的技巧。
4.4.1技巧一:代理函数对象
这是最简单的运用。设立一个代理函数对象,根据条件的不同,将它指向不同的函数,可实现动态改变(即运行时改变)。相信有经验的程序员都了解动态改变函数的便利性。而且在于ActionScript提供了这种便利,运用这个特性可以衍生大量技巧。见示例4-4。
var kingdaFunc:Function;
var sex:String = “male”;
if (sex == “male”) {
kingdaFunc = maleFunc;
} else {
kingdaFunc = famaleFunc;
}
kingdaFunc();
//输出:I am a boy
function maleFunc() {
trace (“I am a boy”);
}
function femaleFunc() {
trace (“I am a girl”);
}
复制代码
4.4.2技巧二:建立函数执行队列
比如说,我有一个对象,我想根据不同的情况对它进行一系列的操作。但是有时需要所有的操作,有时有只需要一部分的操作。那么这个较高级的技巧,就能保证代码的高度重用性和简捷。见示例4-5。
示例4-5 建立函数执行队列
var funcAry:Array = new Array();
//将需要的操作步骤加入队列
funcAry.push(aFunc);
funcAry.push(bFunc);
funcAry.push(cFunc);
//供操作的对象
var originObject:Object = new Object();
//需要执行几步由execQueue这个参数决定,在实际工程运用中这个数可能是动态决定的
var execQueue:Number = funcAry.length;
//核心步骤:函数队列执行。实际运用中可以把它包装成一个函数,或者一个类的实例
for (var i:Number =0; i<funcAry.length; i++) {
funcAry (originObject);
}
//trace出执行操作后的originObject里面的内容
for (var j in originObject) {
trace (j + “:” + originObject[j]);
}
//操作步骤a,b,c
function aFunc(eO:Object) {
e0.aFuncExected = true;
trace (“aFunc()”);
}
function bFunc(eO:Object) {
eO.aFuncExected = true;
trace (“bFunc()”);
}
function bFunc(eO:Object) {
eO.aFuncExected = true;
trace (“cFunc()”);
}
复制代码
输出内容为:
aFunc()
bFunc()
cFunc()
aFuncExected:true
bFuncExected:true
cFuncExected:true
复制代码
前3行表明a、b、c3个函数按顺序执行了。后3行表明orginObject确定经过了3步操作,多了3个为true的属性。
笔者提醒:技巧可以再延伸!可以通过一个函数来管理队列里面各个元素的位置,达到改变操作函数的顺序。比如,通过一个数组来安排调用顺序。以下代码,紧接着上文的代码例子。
var operationAry:Array = [2,1,0];
for (var k:Number = 0; k<operationAry.length;k++) {
funcAry[operationAry[k]](originObject);
}
/*输出:
cFunc()
bFunc()
aFunc()
*/
复制代码
这样函数就通过2、1、0这样的倒序来执行操作。
这个技巧还有很多可以延伸的地方,比如说动态控制操作函数的参数多等,甚至可以通过外部数据(如XML)运行时改变函数执行顺序。大家可以自己研究扩展。
4.4.3技巧三:利用函数返回
函数有一个proxyObject对象,我们希望根据proxy对象的内容来确定一个方法,处理myObject对象。
当proxyObject是字符串时,我们又希望根据字符串的内容来确定返回不同的函数(或方法)。这些函数参数和类型是不完全相同的。有的可能是一个参数,有的可能是多个参数,不同类型。
那么传统的解决方法——在函数内部调用其他函数——就显得力不从心。即使解决,也不如笔者下面这个chooseFuncBy()函数简捷。缺点当然有,那就是比较灵活,使用者一定要清楚地管理好每个目标函数和判断逻辑。因为这种灵活的编程方式编译器无法检查,是不能查出类型不匹配这种错误的。初学者慎用。见示例4-6。
示例4-6 利用函数返回函数
//通过A调用只有一个参数的aFunc();
chooseFuncBy (“A”) (“A func has only one parameter.”);
//输出:aFunc(): A func has only one parameter.
//通过B调用有两个参数的bFunc();
chooseFuncBy(“B”) (“B func has two parameters.”,”No.2 parameter”);
//输出:bFunc():B func has two parameters.one more Parameter:No.2 parameter
//字符串不符,默认函数
chooseFuncBy(“wu lala”)(“I choose A function”);
//输出:Welcome to Kingda.org!My blog
var withObj:Object = new Object();
var myObj:Object =
{name:”黑羽”,blog:”http://www.kingda.org”, hobby:”Starcraft”};
chooseFuncBy(withObj)(myObj);
/*输出:
objectFunc();
name:黑羽
blog:http://www.kingda.org
hobby:Strarcraft
*/
function chooseFuncBy(input:*):Function {
//运用一:利用参数的种类来确定返回的函数
if (!(input is String)) {
return objectFunc;
}
//运用二:根据参数内容来返回函数
switch (input) {
case “A”:
return aFunc;
case “B”:
return bFunc;
default:
return kingdaFunc;
}
//…更多延伸运用:利用参数个数、is确定不同Class的实例来选择函数,等等
}
复制代码
function aFunc(nS:String) :void {
trace (“aFunc():” + nS);
}
function bFunc(nS:String, nP:String) :void {
trace (“bFunc():” + nS + “one more Parameter:”+ nP);
}
function kingdaFunc(…rest) :void {
trace (“Welcome to Kingda.org! My blog”);
}
function objectFunc(kingdaObj:Object) :void {
trace (“objectFunc():”);
for (var i in kingdaObj) {
trace (i + “:” + kingdaObj);
}
}
复制代码
4.4.4技巧四:函数动态添加实例属性
如4.3节所说,使用函数表达式定义的函数也是一个动态类对象。因此,使用函数表达式定义的函数可以动态添加属性和方法。
注意,技巧四和技巧五完全可以用面向对象的方法来解决。从面向对象的角度来说,频繁使用技巧四和技巧五不是一个好的编程习惯。虽然很方便,但由于动态属性的使用使得编译器无法进行类型检查,也使得在复杂代码中的犯错可能性增加,查错难度增大。技巧四和技巧五只是运用在一些特殊的场合,在面向过程的编程中使用稍多一些。
下面来介绍技巧的运用。
例如,利用函数动态属性来计算函数调用次数。当然,你完全可以用这个技巧来干更多更有用的事,笔者只是抛砖引玉做个小例子。
一个游戏中有开火函数shot()。我想知道总共开火了多少次,那么可以添加一个shot函数的动态属性times。注意,引用shot函数动态属性时,只能使用“函数名+数组访问符+属性名”来访问,例:shot[‘times’]。见示例4-7。
示例4-7函数动态添加实例属性
var shot:Function = function ():void {
shot[‘times’] ++;
trace (“Shot():times:”+ shot[‘times’]);
//.. 可以写些其他代码放在这儿
}
shot[‘times’] = 0;
//初始化times
shot();
//输出:Shot():times:1
shot();
//输出:Shot():times:2
shot();
//输出:Shot():times:3
复制代码
4.4.5技巧五:函数对象动态添加实例方法
技巧五就是添加方法了,更有趣一些。函数这么一摆弄之后,函数对象成了“二不像”:不像普通类实例,也不像一个函数。这个技巧可以让我们的函数变得很强大,也会让它更复杂更难以管理。本技巧即使在面向过程编程中,也只建议在小范围内少了运用,不赞成大范围大规模地使用。
见示例4-8,本例中一旦发现shot()函数开火超过3次,就会自动调reload,将开火次数重置为0。
示例4-8 函数对象动态加实例方法
var shot:Function = function():void {
shot[‘times’] ++;
trace (“Shot():times:”+ shot[‘times’]);
shot[‘reload’]();
//shot的其他代码放在这儿
}
shot[‘times’] = 0;
shot[‘reload’] = function () {
trace (“reload:”+ this[‘times’]);
if (this[‘times’] >3) {
this[‘times’] = 0;
}
}
shot[‘reload’]();
shot();
shot();
shot();
shot();
复制代码
shot();
shot();
/*输出:
reload:0
Shot():times:1
reload:1
Shot():times:2
reload:2
Shot():times:3
reload:3
Shot():times:4
reload:4
Shot():times:1
reload:1
Shot():times:2
reload:2
*/
复制代码
写在篇尾的话:可以看出,运用动态添加属性和方法的技巧,可以使Function这个特殊的东西异常强大。而且其灵活程度更是空前,试想如果动态添加的方法返回函数(见4.4.1节第一个技巧)。不要忘了,动态添加的方法可直接访问函数的输入参数,那么其衍生的技巧又有多少种呢?函数又可以变成怎样一种强有力的编程对象呢?只有想不到,没有做不到。这就是Function给我们展示的无穷灵活性。
但是,还是要说的是,技巧终归是技巧,它有其两面性。灵活是它的优点,也是它的缺点。小范围地运用让你爽快无比;大项目中大范围地使用,除非管理得很好,不然会让你头疼欲裂死而后快。
4.5 本章小结函数是面向过程编程的核心元素,也是遥望面向对象编程殿堂的第一个界碑。其重要性不言而喻。
本章讲解了ActionScript3中函数的两种定义法方法:语句定义法和表达式定义法,并花大篇幅详细地说明了二者的不同。并在函数本质一节中,点出了二者在底层实现上的不同。本章还介绍了ActionScript3中新增的函数特色、默认参数和…(rest)关键字。
在函数高级使用技巧中,介绍了ActionScript3函数特有的使用技巧。我们会发现随着不断挖掘函数自身的潜力,在慢慢地开始向面向对象思想靠拢。
相关文章推荐
- Flash ActionScript3 殿堂之路 第四章ActionScript3中的函数及高级使用技巧
- Flash ActionScript 3 殿堂之路学习笔记
- Flash ActionScript3 殿堂之路
- Flash ActionScript3 殿堂之路 第一章:ActionScript3语言介绍与开发环境
- Flash ActionScript3 殿堂之路 第二章 ActionScript3语言基本元素
- Flash ActionScript 3 殿堂之路学习笔记
- 一本好书 Flash ActionScript 3.0高级动画教程
- Flash ActionScript 3.0 动画高级教程 (高清PDF中文版下载)
- C# 的时间戳 在flash actionscript中使用
- C# 的时间戳 在flash actionscript中使用
- actionscript.org上的论坛–找到你在Flash使用/开发过程中问题答案的好地方
- <<Flash.ActionScript.3.0动画高级教程>>
- flash as Actionscript中的数组的使用方法
- 《Flash ActionScript 3.0 动画高级教程》
- Flash CS4中"将动画复制为ActionScript"使用初探
- Flash Action script 学习笔记
- 网页中插入FLASH代码的参数解释与使用技巧
- [FLASH]Understanding ActionScript 3 debugging in Flash
- Google Buzz高级使用技巧