Skip to content

Instantly share code, notes, and snippets.

@thunklife
Created March 13, 2014 16:57
Show Gist options
  • Select an option

  • Save thunklife/9532333 to your computer and use it in GitHub Desktop.

Select an option

Save thunklife/9532333 to your computer and use it in GitHub Desktop.
In "New Rules for JavaScript", Kyle Simpson points out that the anonymous functions used as click handlers are "bloated" closures...
(function IIFE(){
function init(){
var something = "cool",
somethingElse = [1,2,3,4,5,6,7,8],
$btn1 = $("btn1"),
$btn2 = $("btn2"),
$btn3 = $("btn3");
$btn1.click(function hander(evt){
console.log("1", something);
});
$btn1.click(function hander(evt){
console.log(3, something);
});
$btn1.click(function hander(evt){
console.log(3.14, something);
});
}
}());
@thunklife
Copy link
Copy Markdown
Author

I'm not sure I understand the concept of closure bloat. I understand that each anonymous function has access to all of init's variables, but my understanding is that they only close over something. So how does the scope of the other variables create bloat in the anonymous function?

@getify
Copy link
Copy Markdown

getify commented Mar 13, 2014

They technically/academically close over the entire scope, not just individual variables. The fact that they don't seem to lexically reference somethingElse is potentially, implementation-dependent, something the engines might be able to optimize for, where they wouldn't keep somethingElse around prevented from GC. But that's not guaranteed, and there are many cases where even the modern browsers struggle with these sorts of things, so sometimes it's optimized and other times not.

So I teach the strict narrow interpretation, ignoring implementation details, as it's safer to code defensively than to code assuming certain optimizations that are beyond your control.

Also, consider if there was a with, eval, or Function (or even, ugly, a setTimeout(..) or setInterval(..) with a string param for the "code") present in one of those inner functions. It would be impossible for the engine to know if it needed to close over somethingElse or not, so it would have to pessimistically assume that it should.

@getify
Copy link
Copy Markdown

getify commented Mar 13, 2014

Also, an explicit block-scoping could even further help tell the engine "don't keep somethingElse around for the inner functions":

(function IIFE(){
  function init(){
    var something = "cool",
        $btn1 = $("btn1"),
        $btn2 = $("btn2"),
        $btn3 = $("btn3");

    {
      let somethingElse = [1,2,3,4,5,6,7,8];
      // ...
    }

    $btn1.click(function hander(evt){
      console.log("1", something);
    });

    $btn1.click(function hander(evt){
      console.log(3, something);
    });

    $btn1.click(function hander(evt){
      console.log(3.14, something);
    });
  }
}());

@thunklife
Copy link
Copy Markdown
Author

@getify - Thanks for the response! I think I get what you mean now. So this would be an issue even if the function didn't use the value of something, because it's still in scope, correct?

@thunklife
Copy link
Copy Markdown
Author

Makes perfect sense. Thanks.

@getify
Copy link
Copy Markdown

getify commented Mar 13, 2014

Cheers! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment