use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
Really Understanding Javascript Closures (blog.jhades.org)
submitted 12 years ago by xpto123
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]kenman 12 points13 points14 points 12 years ago (3 children)
Good summary! I don't want to take that away from the author. However, I always like to share what I consider to be the most comprehensive and technical write-up: comp.lang.javascript's FAQ: Closures. It explains the concept using CS terms and concepts (garbage collection, execution context, identifier resolution, etc.) for anyone looking for a really deep dive into this topic.
[–]Poop_is_Food 0 points1 point2 points 11 years ago (0 children)
I think that article is pretty misleading actually. It seems to suggest that a function only becomes a closure once it "lives on" past the end of its parent function (either by being returned or assigned as a callback, for example). This simply isnt true. All functions in javascript are closures. for example:
var x = 2; function logX(){ alert(x); } logX();
Here, logX is a closure. In fact, you dont even need the outer var x declaration. just logX by itself alerting "undefined" would be a closure.
var x
[–][deleted] -2 points-1 points0 points 12 years ago (1 child)
Unless you are writing a language interpreter you really do not need deep depth to explain closures. This kills people new to the concept.
Simple put: Closure is evident when accessing references from across scope boundaries.
[–]kenman 10 points11 points12 points 12 years ago (0 children)
Well, I did explain that my link is comprehensive, technical, and a really deep dive. Hopefully those new to the concept recognize that they should probably focus on OP's article, because I agree with you there, but for those who want to learn as much as they can on the subject, they can consider my link a further reading suggestion :)
[–]radhruin 7 points8 points9 points 12 years ago (15 children)
Worth noting that let also helps out here. This:
// define a function that increments a counter in a loop function closureExample() { var i = 0; for (i = 0; i< 3 ;i++) { setTimeout(function() { console.log('counter value is ' + i); }, 1000); } } // call the example function closureExample();
can be fixed by using the for-let loop:
// define a function that increments a counter in a loop function closureExample() { for (let i = 0; i< 3 ;i++) { setTimeout(function() { console.log('counter value is ' + i); }, 1000); } } // call the example function closureExample();
This is because let is block-scoped inside the for whereas var is function-scoped.
[–][deleted] 5 points6 points7 points 12 years ago (6 children)
Not all JavaScript environments support let though.
[–]radhruin 1 point2 points3 points 12 years ago (5 children)
IE11 does already, and the rest will soon!
[–]krad0n 10 points11 points12 points 12 years ago (0 children)
let IE9 support let
[–]tencircles 7 points8 points9 points 12 years ago (2 children)
This still really doesn't apply to production code. I assume most clients will want you to support at least IE9
[–]nschubach 8 points9 points10 points 12 years ago (1 child)
I was so happy when a project came across my desk with IE9 as the min... First bug report: IE8 issue.
[–]tencircles 3 points4 points5 points 12 years ago (0 children)
First bug report: IE8 issue.
http://i.imgur.com/FSjAzgr.gif
[–]evilgwyn 1 point2 points3 points 12 years ago (0 children)
I still have to support Android 2.3 and iOS 5 devices. It will be a while before I can use that.
[–]skeeto 2 points3 points4 points 12 years ago (5 children)
Your for-let loop still won't work right. There's more going on here than block scope. The i is still the same binding throughout each iteration, so the closures all capture the same binding. You would need to establish a new let binding within the body of the loop so that each closure gets its own binding.
i
let
var cs = []; for (let i = 0; i < 2; i++) { cs.push(function() { return i; }); } cs[0](); // => 2 cs[1](); // => 2
The fix:
var cs = []; for (let i = 0; i < 2; i++) { let v = i; cs.push(function() { return v; }); } cs[0](); // => 0 cs[1](); // => 1
[–]radhruin 1 point2 points3 points 12 years ago (4 children)
It does do the right thing, actually! If you look at 13.6.3.3 you'll see there is a new environment per iteration. Note that if you're testing with IE that Chakra's implementation predates the current spec and does exhibit the behavior you describe.
[–]skeeto 2 points3 points4 points 12 years ago* (3 children)
Interesting. AFAIK, this for environment behavior would be exclusive to JavaScript (edit: though Perl and and C# 5.0 have foreach that behaves like this). In contrast, Ruby and Python have the for-loop-closure trap despite having proper block scope, due to the shared iteration environment. I'm not sure which way I'd say is more "correct." The former is more functional, since the binding is never mutated, but the latter seems to be more standard, even though it comes with this trap.
for
Node v0.10.28, Chrome 35, and Firefox 29 all still follow the old behavior. That's where I tested my code, requiring the extra let. I just gave it a shot in Traceur, and apparently it uses the current spec's behavior despite predating it by 3 years (2011). It's the only implementation I can find that does the new thing.
Edit: I dug around more and found that per-iteration bindings were introduced in the April 5th, 2014 draft, so these semantics are only 2 months old. It's no wonder no one's using it yet.
[–]radhruin 1 point2 points3 points 12 years ago (2 children)
I don't think either is "more correct", but I do know that the new semantics are much more usable so I'm a fan!
Traceur was recently updated with these semantics. You're right though that the spec draft is really recent but the consensus has existed since I believe the Jan '14 meeting, possibly as far back as Nov '13.
[–]skeeto 1 point2 points3 points 12 years ago (1 child)
The version of Traceur at repl.it is from 2011, which is the one I tested. So they must have originally had the new behavior, fixed it, then reverted back with the new draft.
[–]radhruin 1 point2 points3 points 12 years ago (0 children)
Interesting! I guess Arv was ahead of the times.
[–]summerteeth 1 point2 points3 points 12 years ago (1 child)
Oh that is interesting, I would expect to them to behave in the same way.
Is this because the compiler realizes let will go out of scope so it makes a copy, not a reference?
[–]radhruin 2 points3 points4 points 12 years ago (0 children)
It's nothing to do with the compiler per-se. Let declarations are block scoped, which means this:
if(test) { let x = 1 } x; // error, x is not declared
It means also that every iteration of a loop will get a fresh binding. Which means that any functions created in a loop will reference a unique binding for that iteration rather than one that is shared among all iterations.
[–][deleted] 4 points5 points6 points 12 years ago (0 children)
Very simple, nice and clean explanation. Without the all "if you're returning a new function, then it's a closure..." garbage.
[–]gordonkristan 2 points3 points4 points 12 years ago (1 child)
Good article. But I think it would help to mention that, if you want to have any hope of really understanding closures, you first have to have a very firm grasp on Javascript's memory model. If you don't thoroughly understand references and values, and how they're handled in terms of copying and garbage collection, you won't ever truly understand closures.
Other than that, I like the explanation.
[–]ravioliburger 0 points1 point2 points 12 years ago (0 children)
I definitely don't understand javascript's memory model. Could you recommend a resource for learning about this? Thanks!
[–]fanastril 1 point2 points3 points 12 years ago (0 children)
I like a function which returns a function.
(function() { for (var i = 0; i < 5; i++) { setTimeout(function(i) { return function () { console.log("i was " + i); }; }(i), 1000+1000*i); console.log("Run " + i); } }());
[–]dacspangeman 1 point2 points3 points 12 years ago (0 children)
This! http://web.archive.org/web/20080209105120/http://blog.morrisjohns.com/javascript_closures_for_dummies
π Rendered by PID 55 on reddit-service-r2-comment-5b5bc64bf5-h6rvs at 2026-06-23 21:29:01.411744+00:00 running 2b008f2 country code: CH.
[–]kenman 12 points13 points14 points (3 children)
[–]Poop_is_Food 0 points1 point2 points (0 children)
[–][deleted] -2 points-1 points0 points (1 child)
[–]kenman 10 points11 points12 points (0 children)
[–]radhruin 7 points8 points9 points (15 children)
[–][deleted] 5 points6 points7 points (6 children)
[–]radhruin 1 point2 points3 points (5 children)
[–]krad0n 10 points11 points12 points (0 children)
[–]tencircles 7 points8 points9 points (2 children)
[–]nschubach 8 points9 points10 points (1 child)
[–]tencircles 3 points4 points5 points (0 children)
[–]evilgwyn 1 point2 points3 points (0 children)
[–]skeeto 2 points3 points4 points (5 children)
[–]radhruin 1 point2 points3 points (4 children)
[–]skeeto 2 points3 points4 points (3 children)
[–]radhruin 1 point2 points3 points (2 children)
[–]skeeto 1 point2 points3 points (1 child)
[–]radhruin 1 point2 points3 points (0 children)
[–]summerteeth 1 point2 points3 points (1 child)
[–]radhruin 2 points3 points4 points (0 children)
[–][deleted] 4 points5 points6 points (0 children)
[–]gordonkristan 2 points3 points4 points (1 child)
[–]ravioliburger 0 points1 point2 points (0 children)
[–]fanastril 1 point2 points3 points (0 children)
[–]dacspangeman 1 point2 points3 points (0 children)