nwebb

Flex, Flash, AIR

Quick Reference: Method Closures From The Ground Up

Although for the most part I understood what method closures were all about, if you had asked me to define exactly what one was, I previously would have stumbled, so I thought I’d solidify my knowledge a little by writing a quick post – I’ll keep it as short as possible!

Functions vs Methods
Just to make sure we’re all on the same page, you should know the difference between a function and a method: at its most basic, a function is a block of code that you can execute, and a method is just a function which belongs to an object. So, if I called ball.bounce() I would be calling the bounce method of the ball instance (bounce is a function, and is also a method of the ball instance).

Named vs Anonymous Functions
We can have named functions & anonymous functions. Those of you who have experience with AS2 may be more familiar with anonymous functions than those who don’t.
[as]
//named function (it has the name ‘sayHello’)
function sayHello():void{
trace(“Hello!”);
}

//anonymous function (function without a name)
function():void{
trace(“Hello!”);
}

//Example of using an anonymous function, AS2 stylie!
//The anon function is only called when the user clicks button1
button1.onClick = function(){
trace(“button was clicked”);
}
[/as]

‘this’ keyword
If we’re going to talk about method closures and scope, we should discuss ‘this’. Even though it won’t apply to my final example, it is important to understand.

Because I want to keep this post simple, I will just talk about how it behaves in AS3. What ‘this’ refers to, differs, depending upon whether or not you are using an anonymous or named function.
In AS3 if you use a named function, ‘this’ will always refer to the original context of the function definition (ie to the object on which you initially defined that function). Therefore, if you defined your named function on the main timeline of a Flash movie, ‘this’ would always refer to the root of that movie, and if you defined your named function within an instance of a class, ‘this’ would refer to that class instance.

[as]
//All of this code sits inside an instance of a class named ‘myBall’ …

function sayHello():void{
trace(this + ‘ says hello’);
}

var obj1:Object = new Object();
obj1.sayHello = sayHello;

var obj2:Object = new Object();
obj2.sayHello = sayHello;

obj1.sayHello();//will trace “myBall says hello”
obj2.sayHello();//will trace “myBall says hello”
[/as]
Anonymous functions act slightly differently. In this case it is ‘the object from which the function is being called’ that is represented by ‘this’. That may sound confusing so let me show you an example:
[as]
var obj1:Object = new Object();
obj1.sayHello = function(){
trace(this + ‘ says hello’);
}

var obj2:Object = new Object();
obj2.sayHello = obj1.sayHello; //note what I’m doing here!

obj1.sayHello();//in theory this should trace “obj1 says hello”
obj2.sayHello();//in theory this should trace “obj2 says hello”

[/as]
The code above says “in theory this should trace …”
Both calls would actually trace out [Object object] says hello because we are just creating instance of an Object. That’s not very useful. If we wanted to get a better trace we could give each object a ‘name’ property:
obj1.name = “obj1″;
obj2.name = “obj2″;
then we would change our anonymous function to say:
trace(this.name + ‘ says hello’);
What is important to note is that in the second instance, even though I assign obj1.sayHello to obj2.sayHello, ‘this’ still refers to obj2!

Now let’s define a couple of things and finish off by giving one last example which should illustrate the concept of method closures.

Lexical Environment (definition)
Big phrase, simple meaning: The lexical environment includes all the variables, properties, methods, and objects in the function’s scope chain, along with their values.
Why did you need to know that? Because it simplifies the definition of what a function closure is …

Function Closure (definition)
A function closure is an object that contains a snapshot of a function and its lexical environment.
Function closures retain the scope in which they were defined (remember what we said earlier when discussing ‘this’?). Hopefully the final example should solidify your understanding.

Example of a Function Closure

We’re going to create a named function which returns an anonymous function. The point of this is to show that the anonymous function has access to any arguments (and/or local variables) which were defined (or sent in to) in the named function. The anonymous function still has access to these arguments/variables even after the named function has finished executing! We say it ‘runs in the scope of the named function’.

[as]
/**
* The body of the inner function (anonymous) is not executed at the same time as
* the outer function (‘generator’). However, the inner function has access to the
* outer function’s argument (num1), because it is shares the same
*scope as the outer function.
*/
public function generator(num1:Number):Function
{
return function(num2:Number):Number //function closure defined
{
return num1 + num2;
};
}

//called when Flex’s creationComplete event fires…
public function onCreationComplete():void
{
//create a new function which will accept an argument
//& always add 10 to that argument
var addTen:Function = generator(10);
trace( addTen(5) ); //traces 15
}
[/as]
Okay, so the first time you look at this example it’s fair enough to think “Erm that’s confusing!” I’m sure you wouldn’t be alone in that, so let’s just step through it and I’ll try to explain what’s going on …

Whenever we call ‘generator’ we need to send in a number (‘generator’ is a named function that accepts an argument). ‘Generator’ will create and return an anonymous function, and because the anonymous function is created in the scope of ‘generator’ this anonymous function will have access to the argument we sent in. It continues to have access to it, even after ‘generator’ has finished executing!

So, when do we do this? In the above example we do it upon creationComplete: we create a function called ‘addTen’ (we call ‘generator’, sending in the number 10), and that returns our anonymous function, which, remember, has access to the number 10.

var addTen:Function = generator(10);
This number (10) is the num1 that we refer to in our ‘generator’ function.

When we eventually run ‘addTen’, it expects a parameter (this is the num2 that we refer to in our ‘generator’ function). We send in the parameter, which can be any number (here we send in 5), and it adds that number to 10.

… in other words, our anonymous function ‘remembers’ the number 10, even though the ‘generator’ function into which we sent 10 has already returned.

So What Is A Closure Again?
A closure is formed when an inner function is made accessible outside of the function in which it was contained. It still has access to the arguments and local variables of its outer function, and can be executed after the outer function has returned.

1 comment

1 Comment so far

  1. Juan Manrique October 21st, 2010 12:48 am

    Really nice explanation. Just what I was looking for. Thanks a lot!

Leave a reply