This section discusses how we use the language constructs of ActionScript 3, especially when there are multiple ways to express the same thing.
Table of Contents
Type declarations
Write a type annotation for every constant, variable, function argument, and function return value, even if the annotation is simply :* to indicate “no type”. Annotation is obligatory.
1 2 3 4 5 | // Do this: var value:*; // Not this: var value; |
Use the narrowest type that is appropriate. For example, a loop index should be a int, not a Number, and certainly not an Object or *.
As another example, a mouseDownHandler should declare its argument as event: MouseEvent, not event:Event.
Use int for integers, even if they can’t be negative. Use uint only for RGB colors, bit masks, and other non-numeric values.
Use * only if the value can be undefined. You should generally use Object rather than *, with null being the “object doesn’t exist” value.
If you declare something to be of type Array, add a comment of the form /* of ElementType */ immediately after Array indicate the type of the array elements.
Use Vector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // Do this:
var a:Array /* of String */ = [];
// Not this:
var a:Array = [];
// And this:
function f(a:Array /* of Number */):Array /* of Object */
{
...
}
// Not this:
function f(a:Array):Array |
Literals
undefined
Avoid using this when possible. It is only necessary when dealing with values whose compile-time is type is *, and you should be using * sparingly as well.
int and uint literals
Do not use a decimal point in a integer.
1 2 3 4 5 | // Do this: var temp:int = 2; // Not this: var temp:int = 2.; |
Use a lowercase x and uppercase A-Z in hexadecimal numbers.
1 2 3 4 5 | // Do this: var temp:uint = 0xFEDCBA; // Not this: var temp:uint = 0Xfedcba; |
Always write an RGB color as a six-digit hexadecimal number.
1 2 3 4 5 | // Do this: private const BLACK:uint = 0x000000; // Not this: private const BLACK:uint = 0; |
When dealing with indices, use the value -1 to mean “no index”.
Number literals
If a Number value typically can be fractional, indicate this by using a decimal point, and follow the decimal point by a single trailing zero.
1 2 3 4 5 6 7 | // Do this: alphaFrom = 0.0; alphaTo = 1.0; // Not this: alphaFrom = 0; alphaTo = 1; |
However, don’t do this for pixel coordinates, which are by convention integral even though they can in principle be fractional.
1 2 3 4 5 | // Do this: var xOffset:Number = 3; // Not this: var xOffset:Number = 3.0; |
Use e, not E, when using exponential notation.
1 2 3 4 5 | // Do this: 1.0e12 // Not this: 1.0E12 |
Use the default value NaN as the “not set” value for a Number.
String literals
Use quotation marks (double quotes), not apostrophes (single quotes), to delimit strings, even if that string contains a quotation mark as a character.
1 2 3 4 5 | // Do this: "What's up, \"Big Boy\"?" // Not this: 'What\'s up, "Big Boy"?' |
Use \u, not \U, for unicode escape sequences.
Array literals
Use Array literals rather than new Array().
1 2 3 4 5 6 7 8 9 10 11 | // Do this: [] // Not this: new Array() // And this: [ 1, 2, 3 ] // Not this: new Array(1, 2, 3) |
Use the Array constructor only to allocate an array of a prespecified size, as in new Array(3), which means [ undefined, undefined, undefined ], not [ 3 ].
Object literals
Use Object literals rather than new Object().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // Do this:
{}
// Not this:
new Object()
// And this:
o = { a: 1, b: 2, c: 3 };
// Not this:
o = new Object();
o.a = 1;
o.b = 2;
o.c = 3;
// Or this:
o = {};
o.a = 1;
o.b = 2;
o.c = 3; |
Function literals
Avoid using function literals to define anonymous functions; use a class method or package function instead.
If you must use a function literal, declare a return type, and terminate the last statement inside the function block with a semicolon.
1 2 3 4 5 | // Do this:
function(i:int):void { doIt(i - 1); doIt(i + 1); }
// Not this:
function(i:int) { doIt(i - 1); doIt(i + 1) } |
it is source of memory leak, so, don’t do it
RegExp literals
Use the literal notation rather than constructing a RegExp instance from a String.
1 2 3 4 5 6 | // Do this:
var pattern:RegExp = /\d+/g;
// Not this:
var pattern:RegExp = new RegExp("\\d+", "g");
XML and XMLList literals |
Use the literal notation rather than constructing an XML instance from a String.
1 2 3 4 5 | // Do this:
var node:XML = <name first="Jane" last="Doe"/>;
// Not this:
var node:XML = new XML("<name first=\"Jane\" last=\"Doe\"/>"); |
Use double-quotes rather than single-quotes around XML attribute values:
1 2 3 4 5 | // Do this: var node:XML = <name first="Jane" last="Doe"/>; // Not this: var node:XML = <name first='Jane' last='Doe'/>; |
Class literals
Use a fully-qualified class literal only if necessary to disambiguate between two imported classes with the same unqualified name.
1 2 3 4 5 6 7 8 9 | // Do this: import mx.controls.Button; ... var b:Button = new Button(); // Not this: import mx.controls.Button; ... var b:Button = new mx.controls.Button(); |
But here a fully-qualified name is required and therefore appropriate:
1 2 3 4 | import mx.controls.Button; import my.controls.Button; ... var b:Button = new mx.controls.Button(); |
Expressions
Parentheses
Don’t use unnecessary parentheses with common operators such as +, -, *, /, &&, ||, <, <=, >, >=, ==, and !=.
1 2 3 4 5 6 7 8 9 10 11 | // Do this: var e:Number = a * b / (c + d); // Not this: var e:Number = (a * b) / (c + d); // And this: var e:Boolean = a && b || c == d; // Not this: var e:Boolean = ((a && b) || (c == d)); |
The precedence rules for other operators are harder to remember, so parentheses can be helpful with them.
Coercion
Don’t compare a Boolean value to true or false; it already is one or the other.
1 2 3 4 5 6 7 8 9 10 11 | // Do this: if (flag) // Not this: if (flag == true) // Do this: var flag:Boolean = a && b; // Not this: var flag:Boolean = (a && b) != false; |
Explicitly coerce a Number, String, XML, XMLList, Array, Object, or * to a Boolean, because these types have multiple values which might reasonably be thought to coerce to false and it is difficult to remember which ones actually do coerce to false in AS3.
1 2 3 4 5 | // Do this: if (s != null && s != "") // Not this: if (s) |
Let subclasses of Object (e.g., UIComponent) coerce implictly to Boolean, because it is obvious that only the null value coerces to false and all others coerce to true. (Note: Object and its subclasses cannot store the value undefined.)
1 2 3 4 5 6 7 8 9 10 11 | // Do this: if (child) // Not this: if (child != null) // And this: if (!child) // Not this: if (child == null) |
Prefer the use of a cast to the use of the as operator. Use the as operator only if the coercion might fail and you want the expression to evaluate to null instead of throwing an exception.
1 2 3 4 5 | // Do this: IUIComponent(child).document // Not this: (child as IUIComponent).document |
Comparison
Write comparisons in the order that they read most naturally:
1 2 3 4 5 6 | // Do this: if (n == 3) // "if n is 3" // Not this: if (3 == n) // "if 3 is n" ++ and -- operators |
Ternary operator
Use a ternary operator in place of a simple if/else statement, especially for null checks:
1 2 3 4 5 6 7 | // Do this:
return item ? item.label : null;
// Not this:
if (!item)
return null;
return item.label; |
But don’t use nested ternary operators in place of complex if/else logic.
1 2 3 4 5 6 7 8 9 10 | // Do this:
if (a < b)
return -1;
else if (a > b)
return 1;
else
return 0;
// Not this:
return a < b ? -1 : (a > b ? 1 : 0); |
new operator
Use parentheses after the class reference, even if the constructor takes no arguments.
1 2 3 4 5 | // Do this: var b:Button = new Button(); // Not this: var b:Button = new Button; |
Statements
Terminate each statement with a semicolon.
1 2 3 4 5 6 7 8 9 | // Do this: a = 1; b = 2; c = 3; // Not this: a = 1 b = 2 c = 3 |
import statements
Import specific classes, interfaces, and package-level functions rather than using the * wildcard.
1 2 3 4 5 6 | // Do this: import mx.controls.Button; import flash.utils.getTimer; // Not this: import mx.core.*; |
if statements
If the various branches of an if/else statement involve single statements, don’t make them into blocks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // Do this:
if (flag)
doThing1();
// Not this:
if (flag)
{
doThing1();
}
// And this:
if (flag)
doThing1();
else
doThing2():
// Not this:
if (flag)
{
doThing1();
}
else
{
doThing2();
} |
But if any branch has multiple statements, make all of them into blocks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // Do this:
if (flag)
{
doThing1();
}
else
{
doThing2();
doThing3();
}
// Not this:
if (flag)
doThing1();
else
{
doThing2();
doThing3();
} |
When doing multiple error checks, use sequential if statements that test for failure and return early. The successful execution flow is then down the page, with the succesful return at the end of the method. Do not use nested tests for success, which make the execution flow drift across the page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // Do this:
if (!condition1)
return false;
...
if (!condition2)
return false;
...
if (!condition2)
return false;
...
return true;
// Not this:
if (condition1)
{
...
if (condition2)
{
...
if (condition3)
{
...
return true;
}
}
}
return false; |
for statements
Make the body of a for loop be a block, even if it consists of only one statement.
1 2 3 4 5 6 7 8 9 | // Do this:
for (var i:int = 0; i < 3; i++)
{
doSomething(i);
}
// Not this:
for (var i:int = 0; i < 3; i++)
doSomething(i); |
Store the upper limit for a for-loop variable in a local variable so that it isn’t re-evaluated every time through the loop (unless, of course, it needs to be re-evaluated on each interation).
1 2 3 4 5 6 7 8 9 10 11 12 | // Do this:
var n:int = a.length;
for (var i:int = 0; i < n; i++)
{
...
}
// Not this:
for (var i:int = 0; i < a.length; i++)
{
...
} |
Declare the loop var inside the parentheses of the for statement, unless it is reused elsewhere.
1 2 3 4 5 6 7 8 9 | // Do this:
for (var i:int = 0; i < 3; i++)
// Not this:
var i:int;
for (i = 0; i < 3; i++)
{
...
} |
while statements
Make the body of a while loop be a block, even if it consists of only one statement.
1 2 3 4 5 6 7 8 9 | // Do this:
while (i < n)
{
doSomething(i);
}
// Not this:
while (i < n)
doSomething(i); |
do statements
Make the body of a do loop be a block, even if it consists of only one statement.
1 2 3 4 5 6 7 8 9 10 11 | // Do this:
do
{
doSomething(i);
}
while (i < n);
// Not this:
do
doSomething(i);
while (i < n); |
switch statements
Make the body of each case clause, and of the default clause, be a block. Put the break or return statement within the block, not after it. If you are returning, don’t put a break after the return. Treat the default clause similarly to the case clauses; break or return from it rather than falling through the bottom of the switch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // Do this:
switch (n)
{
case 0:
{
foo();
break;
}
case 1:
{
bar();
return;
}
case 2:
{
baz();
return;
}
default:
{
blech();
break;
}
}
// Not this:
switch (n)
{
case 0:
foo();
break;
case 1:
{
bar();
}
break;
case 2:
baz();
return;
break;
default:
blech();
} |
return statements
Do not enclose a return value in unnecessary parentheses.
1 2 3 4 5 | // Do this: return n + 1; // Not this: return (n + 1); |
Returning from the middle of a method is OK.
Declarations
Don’t declare multiple constants or variables in a single declaration.
1 2 3 4 5 6 | // Do this: var a:int = 1; var b:int = 2; // Not this: var a:int = 1, b:int = 2; |
The override keyword
If present, put this first, before the access specifier.
1 2 3 4 5 | // Do this: override protected method measure():void // Not this: protected override method measure():void |
Access specifiers
Put an explicit access specifier everywhere that one is allowed. Do not use the fact that internal is the implicit access specifier if none is written.
Before making an API public or protected, think hard about whether it is really needs to be. Public and protected APIs must be documented. They must also be supported for several releases before being formally deprecated.
The static keyword
If present, put this after the access specifier.
1 2 3 4 5 | // Do this: public static const MOVE:String = "move"; // Not this: static public const MOVE:String = "move"; |
The final keyword
If present, put this after the access specifier.
1 2 3 4 5 | // Do this: public final class BoxDirection // Not this: final public class BoxDirection |
Declare all “enum classes” to be final.
Constants
All constants should be static. There is no reason to use an instance constant, since all instances would store the same value.
1 2 3 4 5 | // Do this: public static const ALL:String = "all"; // Not this: public const ALL:String = "all"; |
Variables
If a variable needs to be initialized to a non-default value, do this in the declaration, not in the constructor.
1 2 3 4 5 6 7 8 9 10 11 12 | // Do this:
private var counter:int = 1;
// Not this:
private var counter:int;
...
public function MyClass()
{
super();
...
counter = 1;
} |
Local variables
Declare local variables at or just before the point of first use. Don’t declare them all at the top of the function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Do this:
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);
}
// Not this:
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);
} |
Declare local variables only one per function. ActionScript 3 doesn’t have block-scoped locals.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // Do this:
var a:int;
if (flag)
{
a = 1;
...
}
else
{
a = 2;
...
}
// Not this:
if (flag)
{
var a:int = 1;
...
}
else
{
var a:int = 2;
...
}
// And this:
var i:int;
for (i = 0; i < n; i++)
{
...
}
for (i = 0; i < n; i++)
{
...
}
// Not this:
for (var i:int = 0; i < n; i++)
{
...
}
for (var i:int = 0; i < n; i++)
{
...
} |
Classes
If a class simply extends Object, omit the extends Object clause.
The only “bare statements” in a class should be calls to static class initialization methods, such as loadResources().
Constructors
If a classes has instance members, write a constructor, and make it explicitly call super(), even if it does nothing else.
If the constructor takes arguments that set instance vars, give the the same names as the instance vars.
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Do this:
public function MyClass(foo:int, bar:int)
{
this.foo = foo;
this.bar = bar;
}
// Not this:
public function MyClass(fooVal:int, barVal:int)
{
foo = fooVal;
bar = barVal;
} |
Don’t set the classes’ instance vars in the constructor; do this in the declarations of the instance vars. However, if you need to reset the values of inherited instance vars, do this in the consturctor.

Recent Comments