JavaScript Method Closures

I was further convinced this week that the world needs JASPA when my Flash developer colleague asked me about closures in JavaScript. He’s been knee-deep in AS3 for almost a year, so JavaScript must seem rather weak now.

Unlike JavaScript and AS2, AS3 supports method closures implicitly; so I made sure they were built into the JAS language. Such a thing is not native to JavaScript so the JASPA compiler automatically generates a call to helper function jaspa.closure whenever an object’s method is referenced.

If you’ve ever used Delegate.create in AS2, then you’ve encountered this issue. If you don’t see the problem, consider this example in JavaScript:

  1. var Cat = function(){
  2.      this.voice = ‘Miaow’;
  3. }
  4. Cat.prototype.speak = function(){
  5.      alert( this.voice );
  6. }
  7.  
  8. var Sammy = new Cat;
  9. Sammy.speak(); // alerts “Miaow”
  10.  
  11. var Callback = Sammy.speak;
  12. Callback(); // alerts undefined

As soon as we’ve created a reference to the function member, we’ve severed it from its owner, so when we call it, it’s not being called on the object. In JavaScript and AS2 we need to use a method like Delegate.create to explicitly create a closure. Here’s an example:

  1. function makeClosure( obj, func ){
  2.      var closure = function(){
  3.          return func.apply( obj, arguments );
  4.      }
  5.      closure.apply = function( obj, args ){
  6.          return func.apply( obj, args );
  7.      }
  8.      closure.call = function( obj ){
  9.             var args = [];
  10.              for( var i = 1; i < arguments.length; i++ ){
  11.                  args.push( arguments[i] );
  12.              }
  13.             return func.apply( obj, args );
  14.      }
  15.      return closure;
  16. }

It’s basically a wrapper function which seals in the original arguments. Additionally apply and call must be overridden or calling them directly will spoil the party. Try it with the Cat example and you’ll see the desired result.

  1. var Callback = makeClosure( Sammy, Sammy.speak );
  2. Callback(); // alerts “Miaow”