with Imagination: by Dustin Diaz

./with Imagination

A JavaScript, CSS, XHTML web log focusing on usability and accessibility by Dustin Diaz

Scoping anonymous functions

Tuesday, May 6th, 2008

This is obviously a no-brainer in that knowing something like this works in JavaScript, but it never really occurred to me to even do such a thing until today. Take the following example which ‘calls’ the anonymous function within a unique scope:

Scoping anonymous funcitons

var o = 'hello world';

(function() {
  alert(this);
}).call(o);

It seems ridiculous (in a good way), but it works!

So what’s this mean?

It’s actually a big deal. Think about how many times you’ve lost your desired scope due to being inside the scope of another function. Confused? How many times have you done the following:

Pitfalls anonymous functions

// timeout functions
function Constructor() {
  this.foo = 'bar';
  var that = this;
  this.timerId = window.setTimeout(function() {
    alert(that.foo);
  }, 10000);
}

// local functions
Constructor.prototype.getFoo = function() {
  var that = this;
  var getInternalFoo = function() {
    return DED.isString(that.foo) ? that.foo : 'new foo';
  }();
};

Ok, still not a huge deal, but we can clean up the code a bit, and I would sway from using this on non-anonymous functions where scope should be explicitly defined by the author. Here’s how we can rewrite the code above without using the silly old this = that convention.

Rewritten with proper scope


// local functions
Constructor.prototype.getFoo = function() {
  var getInternalFoo = function() {
    return (DED.isString(this.foo) ? this.foo : 'new foo';
  }.call(this);
};

Ok, what about function callbacks that need scope inducing

(Hehe. Scope inducing, that sounds funny… (anyway)) As you noticed above in the first example with the setTimeout, the first argument takes in a function callback which is different than simply immediately invoking a function. Funny enough, the work around for this is to…. (yeah you guessed it), add another closure! Note the two following snippets of code. The first immediately executes and alerts “hello world”, the second waits for five seconds, and does likewise:

Scoping it up

var o = 'hello world';

// first snippet
(function() {
  alert(this);
}).call(o);

// second snippet
window.setTimeout(function() {
  (function() {
    alert(this);
  }).call(o);
}, 5000);

Pretty fun, huh? Yeah, I thought so too. Cheers.

15 Responses to “Scoping anonymous functions”

  1. Nick Fletcher

    While I agree that this is pretty cool, I’m not sure I prefer it to the that = this convention. Seems like more code to me and something that will definitely confuse a novice JS programmer (not that the that = this convention wouldn’t).

  2. Wesley Walser

    I think there is either an extra paren before DED, or a missing paren before the ;.

    return (DED.isString(this.foo) ? this.foo : ‘new foo’;

    Always happy to see JavaScript another excellent JavaScript writeup, great stuff!

  3. Dustin Diaz

    thanks for the small catch. It’s corrected.

  4. Marc Grabanski

    Ooo… nice trick.

  5. John Larsen

    Wow. I’ve just finished writing some tutorials on this stuff (about 5 mins ago!) and up pops this great example. Nice.

  6. Byron

    heh, I was playing with this idea yesterday, Function.apply() and Function.call() are very nice.

  7. Dustin Diaz

    @John: Go figure :) Suppose there was a movement in the JavaScript zen force?

    @Bryon: Indeed, they’re pretty rad.

  8. Handy Javascript Scoping Trick - Standard Deviations

    […] Javascript function scoping trick from Dustin Diaz, master of cool Javascript tricks. His Javascript Video Tutorials were the first time I was exposed […]

  9. Tore Darell

    I find that using a bind function for scope inducing is both short and clear in its purpose:

    window.setTimeout(function() {
    alert(this);
    }.bind(o), 5000);

    It’s also noob friendly in that the abstraction works quite well and they don’t have to know about the implementation:

    Function.prototype.bind = function(o){
    var fn = this;
    return function(){
    return fn.apply(o, arguments);
    };
    };

  10. leveille

    @Tore: Though I like the usage of bind, I believe Dustin was trying to move away from the that = this convention (which is really what bind is doing).

    @Dustin: Great writeup. This made a light go off for me and brought visions of multiple code segments that can be cleaned up as a result. Thanks.

    Also, didn’t you mean “the silly old that = this convention” instead of “the silly old this = that convention”. Not nitpicking, just thought you’d want to know.

  11. qrayg

    What are “funcitons”? :P

  12. Nick Fletcher

    I do like that solution, Tore.

    Although I would call the function “scope” instead of “bind”. I think “bind” is commonly used for adding event listeners to elements.

  13. Dustin Diaz

    @leville: Haha. Yes, I did flip those accidentally :) My bad. But ya’ll know what I meant.

  14. jay

    “obviously a no-brainer”? Wow, I think it is brilliant. Good work Dustin, I am going to use it right now!

  15. Mariusz Nowak

    I’m not sure do I get your idea.
    Following:
    Constructor.prototype.getFoo = function() {
    var that = this;
    var getInternalFoo = function() {
    return DED.isString(that.foo) ? that.foo : 'new foo';
    }();
    };

    in a real world every programmer would write as:
    Constructor.prototype.getFoo = function() {
    return DED.isString(this.foo) ? this.foo : 'new foo';
    };

    .. and I don’t see solution for:
    function Constructor() {
    this.foo = 'bar';
    var that = this;
    this.timerId = window.setTimeout(function() {
    alert(that.foo);
    }, 10000);
    };

    in this case we’re passing function to be called later so we need to go ‘that=this’ way..

    What I’m missing?

Leave a Reply

Phone Number:

If you're about to post code in your comment, please wrap your code with the tag-combo <pre><code>. Also please escape your html entities - otherwise they will be stripped out. I recommend using postable.

Get "JavaScript Design Patterns"

"As a web developer, you'll already know that JavaScript™ is a powerful language, allowing you to add an impressive array of dynamic functionality to otherwise static web sites. But there is more power waiting to be unlocked--JavaScript is capable of full object-oriented capabilities, and by applying OOP principles, best practices, and design patterns to your code, you can make it more powerful, more efficient, and easier to work with alone or as part of a team."

Buy JS Design Patterns from Amazon.com Buy JS Design Patterns from Apress

Flickr

Submit a Prototype

All content copyright © 2003 - 2007 under the Creative Commons License. Wanna know something? Just ask.

About | Archives | Blog Search

[x] close

Loading...

Submit a prototype

By checking this prototype I agree that I am not submitting false credentials, pornography, or a hate crime website. I also understand that by submitting my entry I may or may not be accepted, and if accepted, my entry may be taken down at any given time if I violate these terms.