One of the most powerful idioms available in JavaScript is the anonymous function closure: e.g. (function(){})();. If you are unfamiliar with this, it simply creates an anonymous scope bubble that can be used to prevent automatic global variables, or trick JavaScript into allowing private variables. Unfortunately, this idiom isnt available in ActionScript 2.0. It simply doesnt work. (As of ActionScript 3.0, it works perfectly.)
This means that, on the surface, the only way to prevent time line variables from being constantly created is an init function of sorts. (ActionScript 2.0 has a pseudo global object which is the main time line of a movie level, and a totally global object named _global.) This also means that private variables are restricted to the creation of object classes. I personally get annoyed at times with classes in ActionScript. One of the things that has always bugged me with ActionScript 2.0 and the introduction of classes is that they are hard to make portable. (I work on no less than 3 computers in a single week, and 4-5 when on business trips, so portability is paramount to my work.) Rather than being able to simply include the classes in the same folder as the flash working file (*.fla), you must specify where on the computer the includes are. This is just annoying if you work on the file on several different computers. There are a couple of ways to avoid naming the class include folder on each computer, but they are as much of a pain as the default method. Fortunately, there is a solution.
To reiterate, while this works in JavaScript and ActionScript 3.0, it will not in ActionScript 2.0:
(function(){ //statements })(); var myFunc = (function(){ var hiddenVar = "hidden"; return function() { return hiddenVar; } })(); hiddenVar //undefined myFunc.hiddenVar; //undefined myFunc(); //returns "hidden"
The good news about ActionScript 2.0 is that it retains the ability to pass anonymous functions as variables to another function. Like so:
var myArray = [5,1,6,23,15]; var sortedArray = myArray.sort(function(a, b){ return a - b; }); trace(sortedArray); //returns [1, 5, 6, 15, 23]
Knowing this, we can emulate anonymous function closures in ActionScipt 2.0. First we will create a global function that returns the function passed to it.
_global.closure = function(f) { return f; }
To use it, you treat it the same as you would the parenteses in the javascript idiom:
closure(function(){ //statements })();
Changing the name to something shorter will make this more practical and the code a little cleaner.
_global.$ = function(f) { return f; } $(function(){ //statements })();
Given this new ability, we can now apply anonymous closures to our script without littering the time line object with useless variables.
Lets use a hypothetical situation to illustrate how we might use the anonymous closure. In this script, we want to make 5 buttons that each need to trace their respective number when you click them. We could code each button individually, but that is messy and doesn't promote good code reuse. Instead, lets make a loop that makes all the buttons work, in addition to making it easier to add more buttons.
for (var i = 1; i <= 5; i++) { //for each button this["click" + i + "_btn"].onPress = $(function(n){ //return a function that has access to n via // a closure return function() { //trace the number passed to the parent closure trace(n); } })(i); //pass in current loop iteration for caching }
Now when you press click3_btn, it will trace '3' and click5_btn, '5'. In this way, we avoid creating useless variables inside each button, and we didn't have to create a singular use function.
Earlier I mentioned my slight distaste for how classes were implemented in ActionScript 2.0. Let me first caveat this statement by saying they are extremely useful and are wonderful for individuals or teams that have good version networks and servers. Just for myself and the smaller applications I write, I prefer portable objects. Lets see how we would write a singleton object with private variables and functions:
var bob = $(function () { //--------------------------- //private variables var secret = "you found me"; //--------------------------- //private functions function compare(a, b) { return a > b; } //--------------------------- //constructor var Bob = { //--------------------------- //public members/variables works :true, getSecret :function() { return secret; }, getCompare :function(a, b) { return compare(a, b); } }; //--------------------------- //return object return Bob; })(); //test trace(typeof bob) //returns object trace(bob.works); //returns true trace(bob.getSecret()); //returns the string: you found me trace(bob.secret); //returns undefined trace(bob.getCompare(1, 2)); //returns false trace(bob.compare(1, 2)); //returns undefined function
As you can see with the tests, we have a singleton object with private functions and variables as well as public methods and members. With a little work, using the prototypal inheritance method, we can make this a reusable pseudo class:
var Bob = $(function () { //--------------------------- //private variables var secret = "you found me"; //--------------------------- //private functions function compare(a, b) { return a > b; } //--------------------------- //constructor var Bob = function () { //--------------------------- //public members/variables this.works = true; }; //--------------------------- //public methods Bob.prototype.getSecret = function() { return secret; }; Bob.prototype.getCompare = function(a, b) { return compare(a, b); }; //--------------------------- //return constructor return Bob; })(); //invoke var mybob = new Bob(); //test trace(typeof Bob); //returns function trace(typeof mybob); //returns object trace(mybob.works); //returns true trace(mybob.getSecret()); //returns the string: you found me trace(mybob.secret); //returns undefined trace(mybob.getCompare(1, 2)); //returns false trace(mybob.compare(1, 2)); //returns undefined
So, with a single global function, we can bring the magic of anonymous function closures to ActionScript 2.0. Enjoy!




Page 1 of 1 pages
Previous entry: Parsing a nested or name spaced object from a string in ECMAScript |