function - How do JavaScript closures work? -
how explain javascript closures knowledge of concepts consist of (for example functions, variables , like), not understand closures themselves?
i have seen the scheme example given on wikipedia, unfortunately did not help.
javascript closures beginners
submitted morris on tue, 2006-02-21 10:19. community-edited since.
closures not magic
this page explains closures programmer can understand them — using working javascript code. not gurus or functional programmers.
closures not hard understand once core concept grokked. however, impossible understand reading academic papers or academically oriented information them!
this article intended programmers programming experience in mainstream language, , can read following javascript function:
function sayhello(name) { var text = 'hello ' + name; var = function() { console.log(text); } say(); } sayhello('joe');
an example of closure
two 1 sentence summaries:
a closure 1 way of supporting first-class functions; expression can reference variables within scope (when first declared), assigned variable, passed argument function, or returned function result.
or, closure stack frame allocated when function starts execution, , not freed after function returns (as if 'stack frame' allocated on heap rather stack!).
the following code returns reference function:
function sayhello2(name) { var text = 'hello ' + name; // local variable var = function() { console.log(text); } return say; } var say2 = sayhello2('bob'); say2(); // logs "hello bob"
most javascript programmers understand how reference function returned variable (say2
) in above code. if don't, need @ before can learn closures. programmer using c think of function returning pointer function, , variables say
, say2
each pointer function.
there critical difference between c pointer function , javascript reference function. in javascript, can think of function reference variable having both pointer function as well hidden pointer closure.
the above code has closure because anonymous function function() { console.log(text); }
declared inside function, sayhello2()
in example. in javascript, if use function
keyword inside function, creating closure.
in c , other common languages, after function returns, local variables no longer accessible because stack-frame destroyed.
in javascript, if declare function within function, local variables can remain accessible after returning function called. demonstrated above, because call function say2()
after have returned sayhello2()
. notice code call references variable text
, local variable of function sayhello2()
.
function() { console.log(text); } // output of say2.tostring();
looking @ output of say2.tostring()
, can see code refers variable text
. anonymous function can reference text
holds value 'hello bob'
because local variables of sayhello2()
kept in closure.
the magic in javascript function reference has secret reference closure created in — similar how delegates method pointer plus secret reference object.
more examples
for reason, closures seem hard understand when read them, when see examples becomes clear how work (it took me while). recommend working through examples until understand how work. if start using closures without understanding how work, create weird bugs!
example 3
this example shows local variables not copied — kept reference. kind of keeping stack-frame in memory when outer function exits!
function say667() { // local variable ends within closure var num = 42; var = function() { console.log(num); } num++; return say; } var saynumber = say667(); saynumber(); // logs 43
example 4
all 3 global functions have common reference same closure because declared within single call setupsomeglobals()
.
var glognumber, gincreasenumber, gsetnumber; function setupsomeglobals() { // local variable ends within closure var num = 42; // store references functions global variables glognumber = function() { console.log(num); } gincreasenumber = function() { num++; } gsetnumber = function(x) { num = x; } } setupsomeglobals(); gincreasenumber(); glognumber(); // 43 gsetnumber(5); glognumber(); // 5 var oldlog = glognumber; setupsomeglobals(); glognumber(); // 42 oldlog() // 5
the 3 functions have shared access same closure — local variables of setupsomeglobals()
when 3 functions defined.
note in above example, if call setupsomeglobals()
again, new closure (stack-frame!) created. old glognumber
, gincreasenumber
, gsetnumber
variables overwritten new functions have new closure. (in javascript, whenever declare function inside function, inside function(s) is/are recreated again each time outside function called.)
example 5
this 1 real gotcha many people, need understand it. careful if defining function within loop: local variables closure not act might first think.
function buildlist(list) { var result = []; (var = 0; < list.length; i++) { var item = 'item' + i; result.push( function() {console.log(item + ' ' + list[i])} ); } return result; } function testlist() { var fnlist = buildlist([1,2,3]); // using j prevent confusion -- use i. (var j = 0; j < fnlist.length; j++) { fnlist[j](); } } testlist() //logs "item2 undefined" 3 times
the line result.push( function() {console.log(item + ' ' + list[i])}
adds reference anonymous function 3 times result array. if not familiar anonymous functions think of like:
pointer = function() {console.log(item + ' ' + list[i])}; result.push(pointer);
note when run example, "item2 undefined"
alerted 3 times! because previous examples, there 1 closure local variables buildlist
. when anonymous functions called on line fnlist[j]()
; use same single closure, , use current value i
, item
within 1 closure (where i
has value of 3
because loop had completed, , item
has value of 'item2'
). note indexing 0 hence item
has value of item2
. , i++ increment i
value 3
.
example 6
this example shows closure contains local variables declared inside outer function before exited. note variable alice
declared after anonymous function. anonymous function declared first; , when function called can access alice
variable because alice
in same scope (javascript variable hoisting). sayalice()()
directly calls function reference returned sayalice()
— same done without temporary variable.
function sayalice() { var = function() { console.log(alice); } // local variable ends within closure var alice = 'hello alice'; return say; } sayalice()();// logs "hello alice"
tricky: note say
variable inside closure, , accessed other function might declared within sayalice()
, or accessed recursively within inside function.
example 7
this final example shows each call creates separate closure local variables. there not single closure per function declaration. there closure each call function.
function newclosure(somenum, someref) { // local variables end within closure var num = somenum; var anarray = [1,2,3]; var ref = someref; return function(x) { num += x; anarray.push(num); console.log('num: ' + num + '; anarray: ' + anarray.tostring() + '; ref.somevar: ' + ref.somevar + ';'); } } obj = {somevar: 4}; fn1 = newclosure(4, obj); fn2 = newclosure(5, obj); fn1(1); // num: 5; anarray: 1,2,3,5; ref.somevar: 4; fn2(1); // num: 6; anarray: 1,2,3,6; ref.somevar: 4; obj.somevar++; fn1(2); // num: 7; anarray: 1,2,3,5,7; ref.somevar: 5; fn2(2); // num: 8; anarray: 1,2,3,6,8; ref.somevar: 5;
summary
if seems unclear best thing play examples. reading explanation harder understanding examples. explanations of closures , stack-frames, etc. not technically correct — gross simplifications intended understanding. once basic idea grokked, can pick details later.
final points:
- whenever use
function
inside function, closure used. - whenever use
eval()
inside function, closure used. texteval
can reference local variables of function, , withineval
can create new local variables usingeval('var foo = …')
- when use
new function(…)
(the function constructor) inside function, not create closure. (the new function cannot reference local variables of outer function.) - a closure in javascript keeping copy of local variables, when function exited.
- it best think closure created entry function, , local variables added closure.
- a new set of local variables kept every time function closure called (given function contains function declaration inside it, , reference inside function either returned or external reference kept in way).
- two functions might have same source text, have different behaviour because of 'hidden' closure. don't think javascript code can find out if function reference has closure or not.
- if trying dynamic source code modifications (for example:
myfunction = function(myfunction.tostring().replace(/hello/,'hola'));
), won't work ifmyfunction
closure (of course, never think of doing source code string substitution @ runtime, but...). - it possible function declarations within function declarations within functions — , can closures @ more 1 level.
- i think closure term both function along variables captured. note not use definition in article!
- i suspect closures in javascript differ found in functional languages.
links
- douglas crockford's simulated private attributes , private methods object, using closures.
- a great explanation of how closures can cause memory leaks in ie if not careful.
thanks
if have just learned closures (here or elsewhere!), interested in feedback changes might suggest make article clearer. send email morrisjohns.com (morris_closure @). please note not guru on javascript — nor on closures.
original post morris can found in internet archive.
Comments
Post a Comment