像Ruby一样简易行码:使用Prototype扩展原生对象
AS3是基于ECMAScript标准的语言,Adobe团队在遵从此标准的同时,使其向Java靠拢具有Class-Base的特征,因此,AS3是一门很奇特的语言,它既像Javascript,又像Java(Java与Javascript是两门完全不同的语言)。
1,Ruby的collect方法
Ruiby的行码简易,让很多程序员爱不释手。
#!/usr/bin/ruby
puts [1,2,3,4,5,6].collect{|x| 10*x}
#!/usr/bin/ruby
puts [1,2,3,4,5,6].collect{|x| 10*x}
上例Ruby代码把数组中的每一个元素的值乘以10,然后打印结果。
10
20
30
40
50
10
20
30
40
50
2,在AS3中实现collect方法
那么在AS3中,我们能否以类似的方法(collect)操作数组?答案是可以的。Array本身是动态、可继承对象,我们可以继承它,自己实现collect方法;除此之外,我们还可以使用Prototype扩展Array的API。
Array.prototype.collect = function(f:Function) : Array {
var r:Array = [];
for each(var i:* in this) r.push(f(i));
return r;
};
Array.prototype.setPropertyIsEnumerable('collect', false);
trace( [1,2,3,4,5].collect(function(i:int):int {return i*10;}) );
// output: 10,20,30,40,50
Array.prototype.collect = function(f:Function) : Array {
var r:Array = [];
for each(var i:* in this) r.push(f(i));
return r;
};
Array.prototype.setPropertyIsEnumerable('collect', false);
trace( [1,2,3,4,5].collect(function(i:int):int {return i*10;}) );
// output: 10,20,30,40,50
扩展Prototype实现collect方法,这种手段更加巧妙,但它从效率上讲,它逊于以继承的方式扩展Array。
3,其它对象如何扩展
因为Array是非final对象,所以除了使用扩展原型(prototype)的方法之外,我们还可以使用继承的方法扩展其本身并不支持的API。但是,在AS3中的其它基本对象,例如基元类型String、Number、int等,它们是final对象,是不可被继承的,仅能使用prototype扩展。 因为Array是动态对象,所以直接在Array对象上调用collect方法,并不会引发编译报警,但对于非动态对象,如String、Number等,在调用时需转化为Object对象,例如:
Object(2).minutes().ago();
Object(2).minutes().ago();
或:
var x:* = 2;
x.minutes().ago();
var x:* = 2;
x.minutes().ago();
在AS3中,所有对象均基于Object,任何对象都具有prototype,即任何对象均可以使用原型扩展并不存在的API。
4,Prototype扩展的弊端
方便在企业项目开发中并不是唯一考虑的因素,效率在多数情况下比之占有更大的比重。使用Prototype扩展至少有以下三个方面的弊端:
- 1)屏蔽了编译时强类型检查,代码错误的机率升高,项目风险增大。
- 2)某些对象不得不作额外的类型转换,虽然这种转换并无性能的损耗,但却让你多敲了几个键盘,偏离了简易行码的本宗。
- 3)基于Prototype的继承与Class-Base的继承,在AVM中是两种完全不同的实现,Adobe团队在AVM2中正是为了解决Prototype的低效,才引入了Class-Base的机制,显然这种不被官方、社区推崇的方法并不适当在企业项目中应用。
扩展阅读:Modifying Core Types in ActionScript 3 Using the Prototype Object
2008年5月