Nested Functions
January 11th, 2010As most Flash developers are aware Actionscript 3 supports nested functions. This essentially allows you to have functions within functions… within functions etc. This gives rise to an interesting set of opportunities and pitfalls.
This post won’t go into the pitfalls which are basically variable scope and garbage collection, there are plenty of posts on the net that focus on these two topics, google can help you find them. The purpose of this post is to show how clever use of nested functions can simplify your code.
To illustrate appropriate use of nested functions I am going to use the following example. We have the following data structure:
var data:Array = [
{
image:"img01.png",
link:"http://site1.com"
},
{
image:"img02.png",
link:"http://site2.com"
},
{
image:"img03.png",
link:"http://site3.com"
},
{
image:"img04.png",
link:"http://site4.com"
}
];
Our objective is to load the images, place them on the stage and when the user clicks on them to navigate to the url related to that image. We are also going to assume that we have a nice Image.as class that we have written. This Image.as class extends sprite and takes a single “url” parameter to its constructor to tell it what to load.
Using nested functions this can be done in a few tidy lines of code.
package {
import com.roddeh.media.Image;
import flash.display.Sprite;
import flash.display.MouseEvent;
import flash.net.*;
public class NestDemo extends Sprite{
public function NestDemo(){
var data:Array = [
{
image:"img01.png",
link:"http://site1.com"
},
{
image:"img02.png",
link:"http://site2.com"
},
{
image:"img03.png",
link:"http://site3.com"
},
{
image:"img04.png",
link:"http://site4.com"
}
]
drawImages(data);
}
private function drawImages(data:Array):void{
data.forEach(drawImage);
function drawImage(imgData:*, index:int, arr:Array):void{
var img:Image = new Image(imgData.image);
img.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void{
navigateToURL(new URLRequest(imgData.link), “_blank”);
});
addChild(img);
}
}
}
}
Ok, so you might be thinking “Yeah, that is one way of doing it, but what is the advantage?”. So, here are the advantages IMO:
1. It creates a more concise interface within your classes. When somebody scans over my code they will see a constructor and a single private function named “drawImages”. How the “drawImages” method works may well be irrelevant to them. All, they need to know is that it somehow draws the images based on a data structure. If I had built the same functionality without nested functions then the reader of my code would have had three methods to deal with “drawImages”, “drawImage” and “handleImageClick”.
2. The code does not jump around as much. Something that often irritates me when reading other people’s code is having to scroll up and down a class to work out what is going on. Very often you will see events being handled in a separately declared private function within which there is only a single line of code. Nested functions allow you to neatly package the result of the event with the code that adds the listener.
3. But most importantly, the alternative would have been really ugly. To illustrate how ugly I am going to pseudo-implement the alternative.
package {
import com.roddeh.media.Image;
import flash.display.Sprite;
import flash.display.MouseEvent;
import flash.net.*;
public class NestDemo extends Sprite{
public function NestDemo(){
var data:Array = [
{
image:"img01.png",
link:"http://site1.com"
},
{
image:"img02.png",
link:"http://site2.com"
},
{
image:"img03.png",
link:"http://site3.com"
},
{
image:"img04.png",
link:"http://site4.com"
}
]
drawImages(data);
}
private function drawImages(data:Array):void{
data.forEach(drawImage);
}
private function drawImage(imgData:*, index:int, arr:Array):void{
var img:Image = new Image(imgData.image);
img.addEventListener(MouseEvent.CLICK, handleImageClick);
addChild(img);
}
private function handleImageClick(event:MouseEvent):void{
navigateToURL(new URLRequest(
// Oh s***, what was that link again…
), “_blank”);
}
}
}
So, you may notice that I am actually kinda screwed with the above implementation because I have lost the reference to “imgData” which is what held the relationship between the image I have clicked on and the link to navigate to.
There are of course a number of ways to solve this.
If I can assume that the “Image” class has a “url” property then I could use the “event.target” (which would reference the image), then loop through the “data” array until I found the image that matched. However, I would then also need to store the “data” array in a private variable. Furthermore, I would be assuming that the same image is not being used twice with different links. Assumptions when coding will f*** you up before long
Alternatively I could have written a wrapper class around “Image” or perhaps extended “Image” and called my new class something like “LinkableImage” which takes two parameters: “url” and “link”. But personally I find superfluous classes even more offensive than superfluous functions within a class. Instead of scrolling up and down a class I now have to jump between classes just to work out something really simple.
—–
In conclusion, nested functions when used carefully can really make your life easier. Be aware of garbage collection when using them in conjunction with event listeners but do not be afraid of them.

