遵循一定编码规范能够使源码看起来前后一致、组织良好、更加专业。 本部分内容包括:1. 命名;2. 语言使用 3. 文件组织 4. 格式 5. ASDoc 1. 命名 缩写:能避免就避免,代码清晰永远比减少打字重要;但是也要记住一些标准化了的通用的缩写,比如acc(accessiblility),auto(automatic),impl(implementation),info(infomation),num(number),min(minimum),max(maximum),nav(navigation),regexp(regular expression),util(utility)等等。使用缩写时尽量和Flex保持一致; 首字母缩写词:要么全部大写要么全部小写。当首字母缩写词当成一个标志符或者标志符的开始部分,且这个标志符必须以小写字母开始的时候才采用全部小写的方式。 词语边界:标志符多个单词构成的时候,单词首字母大写,或者词语以下划线隔开,比如LayoutManager,object_proxy;当多个首字母缩写词邻接的时候遵循首字母缩写词规范,但是尽量避免。 指定类型的名字:如果你要将某一个类型组合到一个名字中去,那么把在加在最后,比如命名命名一个border图形可以使用:border,borderSkin,borderShape;最好的名字就是类型的小写比如:Button的实例button。 包命名:使用小写字母,之间大写字母隔开,比如controls,listClasses;包名称最好是名词或者动名词,不要用动词、介词、形容词、副词之类。当一个包的作用是实现某一功能的时候最好使用动名词,比如bingding,logging,messaging,printing;支持组件FooBar的最好写作fooBarClasses; 文件名称:对于重要的API文件,文件名称必须和重要的公开API保持一致,但是include文件不一定要遵循此规则;对于包含文件比如用作Styles的,大写字母开始,各个单词隔开,且在最后加上Styles: BorderStyles.as,ModalTrasparencyStyles.as; 对于资源文件小写字母开始,下划线隔开:icon_align_left.png; 命名空间名称:小写字母、下划线隔开:mx_internal,object_proxy 接口名称:字母“I”开始、大写字母间隔:IList,IFocusManager,iuiD 类名称:大写字母开始、大写字母间隔:Button, FocusManager;Event子类(FoobarEvent),Error子类(FooBarError),皮肤类(FooBarBackground,FooBarBorder,FooBarIcon...),utility类(FooBarUtil,不是FooBarUtils,包是复数,类是单数); 事件名称:小写字母开始、大写字母间隔:move,creationComplete Style名称:小写字母开始,大写字母间隔:color,fontSize; 字符属性枚举值:auto,filesOnly; 常量命名:全部大写字母,下划线间隔:OFF,DEFAULT_WIDTH,如果常量是一个字符串,那么常量命名和常量值保持一致: <public static const FOO_BAR: String = "fooBar">; 属性名命名:小写字母开始,大写字母间隔: i,width,numChildren; 使用i作为选还变量,n作为循环上界;使用j作为循环变量,m作为循环上界: for (var i:int = 0; i < n; i++) { for (var j:int = 0; j < m; j++) { ... } } 使用p作为loop循环的变量: for (var p:String in o) { ... } 如果子类的getter/setter覆盖了基类的getter/setter,但是同时又想继续公开基类的getter/setter,那么这个时候应将基类的属性名前加上“$”作为子类属性名,并且子类的属性名应该标志为final,且除了调用基类getter/setter外不应该做其它的事情: mx_internal final function get $numChildren():int { return super.numChildren; } 存储变量命名:getter/setter属性foo所存储的变量应该是_foo(加上下划线); 方法命名:小写字母开始,每个单词大写字母间隔,应该使用动词:measure(),updatedisplayList();无参方法应该实现为getter/setter,而不应该是getFooBar(),setFooBar();当然,如果getFooBar()是一个需要大量计算的慢速度方法的话就应该命名为findFooBar(),calculateFooBar(),determineFooBar()等等,而不是getter;如果子类的某方法覆盖了基类的某方法,但是同时又想继续公开基类的某方法,那么这个时候应将基类的方法名前加上“$”作为子类方法名,并且子类的方法名应该标志为final,且除了调用基类方法外不应该做其它的事情: mx_internal final function $addChild(child:displayObject):displayObject { return super.addChild(child); } 事件处理器命名:在后面加上Handler:mouseDownHandler();如果事件处理器是用来处理组件的某一个子组件的事件的话,那么就应该把子组件的名称加到最前面,并且用下划线隔开:textinput_focusInHandler() (textinput的focusin事件的handler); 参数命名:setter值使用value:public function set label(value:String):void; 事件参数使用event:protected function mouseDownHandler(event:Event):void; 资源包名称:为某一包服务的资源包名称应该和包的名称保持一致; 资源键名称:小写字母,每个单词大写字母隔开; 杂七杂八:避免使用“object”,因为它不明确;“item”是数据项,不是显示对象;renderer是显示数据项的显示对象;“type”是AS3类型,否则使用“kind”; 2. 语言使用 这个部分讨论AS3的语言构造,尤其当某一事情有多种表示方法的时候; 编译选项:编译的时候要使用-strict –show-actionscript-warnings(flex-config.xml默认); 基于属性的API:应该偏向基于属性的API而不是基于方法的API,因为这对于声明示的MXML来说更加有利; 类型声明:尽量为每个变量、参数、返回值等编写注释;参数类型尽量准确,比如循环变量应该是int,而不是Number,更不是Object;鼠标事件处理器的参数应该是MouseEvent而不是Event;如果值可以是undefined的话那么使用“*”,这种情况下可以使用Object代替,null表示undefined;如果声明变量为Array,则应该使用“/* */”马上注明数组的成员类型:var a:Array /* of String */ = []; function f(a:Array /* of Number */):Array /* of Object */ { ... } 保留字: undefined尽量避免使用; int和uint:整数后面不要加小数点,十六进制用0x开始,后面的字母大写; RGB色通常用六个十六进制数字表示; 索引值-1表示“没有索引项”; Number:通常表示可以带小数,所以即使变量是整数也应该加上一个小数点和一个零,比如alphaFrom = 0.0; alphaTo = 1.0;但是屏幕坐标值不要这样做; 指数计数的时候使用e,比如1.0e12,不要用大写E; String:使用双引号界定字符,即使字符中间包含引号:字符what’up,“Big Boy”?表示为"What's up,/"Big Boy/"?", 而不是’what/’s up “Big Boy”?’; Array:使用“[]”, 而不是new Array(),比如[1,2,3]而不是new Array(1,3);这里在一个数组变量的时候容易出问题,比如一个包含一个值3的数组,如果用new Array(3),那么表示的是建立了一个三个元素的数组[undefined,undefined,undefined], 而不是[3]; Object:使用{}, 而不是new Object();比如{},{a: 1,b: 2,c: 3}; Function:避免使用匿名函数,用类方法或者包方法代替;如果一定要用,那么声明返回值,并且函数体内最后一个语句用分号结尾:function(i:int):void { doIt(i - 1); doIt(i + 1); } RegExp:不要使用正则表达式构造函数创建正则表达式,使用var pattern:RegExp = //d+/g; 而不是var pattern:RegExp = new RegExp("//d+","g"); XML和XMLList:直接使用保留字声明,不要使用构造函数。使用var node:XML = <name first="Jane" last="Doe"/>;而不是var node:XML = new XML("<name first=/"Jane/" last=/"Doe/"/>"); XML属性值要使用双引号括起来,不要使用单引号。 Class:只有当需要在区分两个导入类的时候才使用类的全名, 正确做法(Yes:): import mx.controls.Button; ... var b:Button = new Button(); 错误做法(No:): import mx.controls.Button; ... var b:Button = new mx.controls.Button(); 正确做法: import mx.controls.Button; import my.controls.Button; ... var b:Button = new mx.controls.Button(); 表达式相关:对于通用的操作符(+,-,*,/,&&,||,<,<=,>,>=,==,!=)不要使用不必要的圆括号;其它的优先级不容易记住的可以借助圆括号。 强制类型转换:不要将Boolean变量和true或false比较;显式的将int,uint,Number,String转换为Boolean值,使用if(n !=0 ) 而不是if (n), 使用if (s != null && s != “”)而不是if (s),对于对象引用来说可以隐式转换为Boolean值,使用 if (child) 而不是if (child != null),使用if (!child) 而不是if (child != null);使用强制类型转换而不是as操作符,仅仅当强制转换可能失败并且你希望失败的时候值为null而不是抛出异常。使用iuiComponent(child).document而不是(child as UIComponnet).document; 比较:以更容易理解的方式书写比较表达式: if (n == 3) // "if n is 3"(Yes), if (3 == n) // "if 3 is n"(No); ++ 和 –操作:前缀形式和后缀形式效果一样的时候使用后缀形式,只有当你想在变量在操作之前使用的时候才使用前缀形式; 三元操作符:可以使用三元操作符代替简单的if/else 逻辑,尤其是对null进行判断的时候; return item ? item.label : null (Yes) if (! Item) return null; return item.label; (No) 但是不要使用嵌套的三元操作符; new:即使构造的类不带参数也要使用圆括号:var b:Button = new Button(); (yes) var b:Button = new Button;(No); 声明:每一个声明语句都使用分号结尾。 include:使用include 而不是已废弃的#include,和前面一样,每个声明语句以分号结束;使用相对路径而不是绝对路径; import:导入明确的类,避免使用通配符“*”; use namespace :避免使用,非公开名字空间引用使用“::”: Yes: import mx.core.mx_internal; // Later,in some method... mx_internal::doSomething(); No: import mx.core.mx_internal; use namespace mx_internal; // Later,in some method... doSomething(); if:当if/else 分支只有一句声明的时候,不要用{}括起来; Yes: if (flag) doThing1(); ―――――――――――――――――――――――――――――――――――― if (flag) doThing1(); else doThing2(): ――――――――――――――――――――――――――――――――――――― No: if (flag) { doThing1(); } ――――――――――――――――――――――――――――――――――――― if (flag) { doThing1(); } else { doThing2(); } 但是如果有一个分支有多行语句,那么都用{}括起来: Yes: if (flag) { doThing1(); } else { doThing2(); doThing3(); } ――――――――――――――――――――――――――――――――――――――― No: if (flag) doThing1(); else { doThing2(); doThing3(); } 对于多个错误检查,使用串行的表达方式,检测错误立即返回,正确值最后返回。不要用嵌套的形式,这样会使整个逻辑看起来很凌乱。 Yes: if (!condition1) return false; ... if (!condition2) return false; ... if (!condition2) return false; ... return true; No: if (condition1) { ... if (condition2) { ... if (condition3) { ... return true; } } } return false; for:循环体使用{}括起来,即使只有一行的情况下也是如此。循环上界需要计算的情况下将它存入本地变量,防止多次重复计算。 Yes: var n:int = a.length; for (var i:int = 0; i < n; i++) { ... } No: for (var i:int = 0; i < a.length; i++) { ... } 循环变量的声明放入圆括号内,除非这个变量需要多次重复使用。 Yes: for (var i:int = 0; i < 3; i++) No: var i:int; for (i = 0; i < 3; i++) { ... } while:循环体使用{}括起来,即使只有一行的情况下也是如此。 do:循环体使用{}括起来,即使只有一行的情况下也是如此。 Switch:每一个case语句都用{}括起来,在{}块里面最后加上return 或者 break语句。如果你想返回值,那么使用return。return后面不必加break。default部分和case部分一样: Yes: switch (n) { case 0: { foo(); break; } case 1: { bar(); return; } case 2: { baz(); return; } default: { blech(); break; } } No: switch (n) { case 0: foo(); break; case 1: { bar(); } break; case 2: baz(); return; break; default: blech(); } return:返回值不加不必要的圆括号。在函数的中间返回也是可以的。 声明:一行不声明多个变量。 Yes: var a:int = 1; var b:int = 2; No: var a:int = 1,b:int = 2; override:放在第一个。override protected method measure():void(Yes) protected override method measure():void(No); 存取标志:在用户没有显式声明的情况下存储标志是internal,避免使用默认声明,在必要的地方显式声明。在需要对API进行public或protected声明之前需仔细考虑,因为经过这种类型声明的函数需要建立文档,并且在正式废弃此API之前项目都必须支持此类API。 static:置于存取标志之后。比如public static const MOVE:String = "move"; final:置于存取标志之后。将所有enum类声明为final基本属性和方法(那些$开始的)声明为final。 常量:所有常量都必须声明为static,常量的值是一样的,所以声明为实例化常量没有意义。 变量:如果变量需要初始化一个非默认值,那么在声明的时候就赋值,不要放在类的构造函数里面去。 本地变量:在使用的时候声明,而不是放在函数开始的部分。 Yes: private function f(i:int,j:int):int { var a:int = g(i - 1) + g(i + 1); var b:int = g(a - 1) + g(a + 1); var c:int = g(b - 1) + g(b + 1); return (a * b * c) / (a + b + c); } No: private function f(i:int,j:int):int { var a:int; var b:int; var c:int; a = g(i - 1) + g(i + 1); b = g(a - 1) + g(a + 1); c = g(b - 1) + g(b + 1); return (a * b * c) / (a + b + c); } 本地变量的作用域是整个函数而不是一个块,一个变量在一个函数范围内只需要声明一次。 Yes: var i:int; for (i = 0; i < n; i++) { ... } for (i = 0; i < n; i++) { ... } No: for (var i:int = 0; i < n; i++) { ... } for (var i:int = 0; i < n; i++) { ... } 类:如果类是Object的子类,那么不必要写extends Object; 构造函数:如果类有实例,那么就要编写构造函数,并且在构造函数里显式调用super()。如果构造函数需要对实例属性初始化,那么构造函数的参数名应该和需要初始化的属性名保持一致。 Yes: public function MyClass(foo:int,bar:int) { this.foo = foo; this.bar = bar; } No: public function MyClass(fooval:int,barVal:int) { foo = fooval; bar = barVal; } 不要在构造函数里对类实例变量属性进行初始化,应该在声明的部分这样做。如果需要改变父类的属性值,那么这部分工作应该放到构造函数里面。 接口、命名空间、元数据、属性实现:待定; 3. 文件组织 在每个as文件的开始部分包含版权信息。2008的开源版权信息如下: /////////////////////////////////////////////////////////////////////////////// // // AdobE SYstemS INCORPORATED // copyright 2008 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use,modify,and distribute this file // in accordance with the terms of the license agreement accompanying it. // /////////////////////////////////////////////////////////////////////////////// 注意:这个是80字母宽; package、import 、use namespace声明:待定; 类元数据:按照“块”的形式组织元数据,顺序为:Events,Styles,Effects,Excluded API以及其它元数据。在每个“块”的前面加上一个小的“块”头部,注意,这个头部是40字符宽,且在块名称和//之间有两个空格。在每个块内对元数据按照字母顺序排序,其它的元数据按照元数据标志进行字母排序。 //-------------------------------------- // Events //-------------------------------------- / ** * ASDoc comment. */ [Event /** * ASDoc comment. */ [Event //-------------------------------------- // Styles //-------------------------------------- /** * ASDoc comment. */ [Style /** * ASDoc comment. */ [Style] //-------------------------------------- // Effects //-------------------------------------- /** * ASDoc comment. */ [Effect /** * ASDoc comment. */ [Effect] //-------------------------------------- // Excluded APIs //-------------------------------------- [Exclude(name="horizontalAlign",kind="style")] [Exclude(name="verticalAlign",kind="style")] //-------------------------------------- // Other Metadata //-------------------------------------- [DefaultBindingProperty(source="text",destination="text")] [IconFile("Text.png")] 类声明:待定; Version.as的包含声明:每个类都应该以相对路径的形式包含core/Version.as,这个文件包含static const VERSION:STRING的声明: include “../core/Version.as”; 实现,类初始化:待定; 类常量:AS3不允许Array和Object类型的常量,但是可以用static var的形式声明(不要用static const),之所以放到这个部分说明是因为在概念上讲它们仍然是常量。 类资源、类变量:待定; 类属性:在这里声明static类型的getter和setter,按照属性字母排序,每个属性前用属性名分隔,将getter放置在setter之前; 构造函数、变量:待定; 重写属性(override properties):在这里声明非静态getter和setter,字母排序,属性名隔开,getter在setter之前; 属性:把非静态setter和setter放在这里,字母排序,属性名分隔,getter在setter之前。 重写方法:将重写的非静态方法放在这里。 方法:非静态函数。 重写事件处理器:将重写的事件处理器放到这里。 事件处理器:新的事件处理器。 包外辅助类:待定; 4. 格式: 这个部分讨论Flex框架类的应该以何种格式书写。 行宽:80字符。优点:小屏幕开发者不必水平滚动;比较工具可以并排放置两个文件窗口;字体投影无需滚动;源码无需经过剪裁或者断行就可以打印; 缩进:4空格;配置你的编辑器插入空格而不是Tab,这样允许其它的程序使用不同的缩进策略而不至于影响显式外观,比如NotPad就是8空格缩进; 块分隔符: 大“块”分隔符: //-------------------------------------------------------------------------- // // Overridden methods // //-------------------------------------------------------------------------- 从4列到80列,文本从8列开始; 小“块”分隔符:类里面使用,比如属性之间。形如: //---------------------------------- // visible //---------------------------------- 从4列到70列,字符8列开始; 分隔部分前后放置一个空行; 声明分隔:常量、变量、函数声明由一个空行隔开; /** * @private * Holds something. */ var a:Number; /** * @private */ var b:Number 元数据:Inspectable[a="1",b="2"](Yes), Inspectable[a=1 b=2](No)。 数组索引:中括号前后都不要加空格,a[0] (yes), a[ 0 ] (no); 逗号:逗号后面加入一个空格,使用参数、数组、对象等; 数组赋值:左括号后面和右括号前面加入一个空格,[ 1,3 ] (yes), [1,3],[1,3](no); 多行复杂数组初始化的时候括号对齐; static var numberNames:Array /* of String */ = [ "zero","one","two","three","four","five","six","seven","eight","nine" ]; 对象赋值:在左花括号后面和右花括号前面加上一个空格, 属性和值之间用的逗号后面加上一个空格;{ a: 1,c: 3 }(yes) {a: 1,c: 3},{a:1,b:2,c:3}(no);空对象是个例:{} ;需要多行表示的对象保持属性和括号的对齐: private static var TextStyleMap:Object = { color: true,fontFamily: true,fontSize: true,fontStyle: true,fontWeight: true,leading: true,marginLeft: true,marginRight: true,textAlign: true,textdecoration: true,textIndent: true }; 类型声明:不要在变量、参数,或者函数类型的冒号前后加任何空格: Yes: var n:Number; No: var n : Number; var n: Number; Yes: function f(n:Number):void No: function f(n : Number) : void function f(n: Number): void 操作符和赋值:在赋值操作符、中缀操作符的前后各加一个空格,不要在前缀或者后缀操作符前后加任何空格; 语句行:每个语句一行,块内保持对齐; 函数声明:如果参数需要换行,那么第二行参数和第一行左括号右侧对齐,如果一行放置适当的数目的参数,如果实在无法安排,那么一行放置一个参数。如果第一行一个都没法放,那么将第一个参数放置到第二行,并相对函数声明进行缩进: public function foo(parameter1:Number,parameter2:String,parameter3:Boolean):void public function foo(parameter1:Number,parameter3:Boolean):void public function aVeryLongFunctionName( parameter1:Number,parameter3:Boolean):void 函数调用:f(a,b) (yes) f(a,b),f( a,b ) (no); if表达式:在if后加入一个空格,但是不要在左括号的右侧和右括号的左侧加入任何空格。 yes: if (a < b) no: if(a < b) if( a < b ) if ( a < b ) for表达式:在for后面加入一个空格,但是不要在左括号的右侧和右括号的左侧加入任何空格。 Yes: for (var i:int = 0; i < n; i++) No: for(var i:int = 0; i < n; i++) for( var i:int = 0; i < n; i++ ) for ( var i:int = 0; i < n; i++ ) 如果for表达式需要换行,那么和左括号右侧保持对齐: for (var aLongLoopVariableName:int = aLongInitialExpression; aLongLoopVariableName < aLongUpperLimit; aLongLoopVariableName++) switch语句:在switch后面加入一个空格,但是不要在左括号的右侧和右括号的左侧加入任何空格。 Yes: switch (n) No: switch(n) switch( n ) switch ( n ) 5. ASDoc get和set成对出现,只对第一个 get/set函数归档,一般的归档格式如下: /** * @private * The backing variable for the property. */ private var _someProp:Foo; /** * Place all comments for the property with the getter which is defined first. * Comments should cover both get and set behavior as appropriate. */ public function get someProp():Foo { ... } /** * @private */ public function set someProp(value:Foo):void { ... } ASDoc注释适用于类内的结构同时也适用于元数据标签,所以注意你的注释应该适合特定的目标。如果你标志一个属性为绑定,那么你的属性注解应该在get函数之前,而不是绑定标签的前面。 Yes: [Bindable("somePropChanged")] /** * Comments for someProp */ public function get someProp():Foo No: /** * Comments for someProp */ [Bindable("somePropChanged")] public function get someProp():Foo
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。