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. text eval can reference local variables of function, , within eval can create new local variables using eval('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 if myfunction 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

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

Popular posts from this blog

java - Static nested class instance -

c# - Bluetooth LE CanUpdate Characteristic property -

JavaScript - Replace variable from string in all occurrences -