Closures Explainned - Muito Bom

Embed Size (px)

Citation preview

  • 8/13/2019 Closures Explainned - Muito Bom

    1/9

    http://www.mollypages.org/misc/jsclo.mp

    Table of contents

    1. Good/reference articles2. Preliminary note: Nested functions3. Closures4. When are closures useful ?5. Browser specific hacks and bugs

    1. Good/reference articles

    First, read the following links:

    http://blog.morrisjohns.com/javascript_closures_for_dummies.html http://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_

    Closures http://www.jibbering.com/faq/faq_notes/closures.html http://laurens.vd.oever.nl/weblog/items2005/closures/ http://www.codeproject.com/KB/scripting/leakpatterns.aspx http://msdn.microsoft.com/en-us/library/bb250448(VS.85).aspx http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx

    2. Preliminary note: Nested functions

    A nested function is defined within another function. function foo() { function bar() { } }

    function baris notreachable from outside function fooby saying

    something like: foo.bar()

    Inner functions can be exposed outside the outer function. function foo() { bar= function () { } }

    http://www.mollypages.org/misc/jsclo.mp#1http://www.mollypages.org/misc/jsclo.mp#1http://www.mollypages.org/misc/jsclo.mp#2http://www.mollypages.org/misc/jsclo.mp#2http://www.mollypages.org/misc/jsclo.mp#3http://www.mollypages.org/misc/jsclo.mp#3http://www.mollypages.org/misc/jsclo.mp#4http://www.mollypages.org/misc/jsclo.mp#4http://www.mollypages.org/misc/jsclo.mp#5http://www.mollypages.org/misc/jsclo.mp#5http://blog.morrisjohns.com/javascript_closures_for_dummies.htmlhttp://blog.morrisjohns.com/javascript_closures_for_dummies.htmlhttp://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closureshttp://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closureshttp://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closureshttp://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closureshttp://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closureshttp://www.jibbering.com/faq/faq_notes/closures.htmlhttp://www.jibbering.com/faq/faq_notes/closures.htmlhttp://laurens.vd.oever.nl/weblog/items2005/closures/http://laurens.vd.oever.nl/weblog/items2005/closures/http://www.codeproject.com/KB/scripting/leakpatterns.aspxhttp://www.codeproject.com/KB/scripting/leakpatterns.aspxhttp://msdn.microsoft.com/en-us/library/bb250448(VS.85).aspxhttp://msdn.microsoft.com/en-us/library/bb250448(VS.85).aspxhttp://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspxhttp://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspxhttp://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspxhttp://msdn.microsoft.com/en-us/library/bb250448(VS.85).aspxhttp://www.codeproject.com/KB/scripting/leakpatterns.aspxhttp://laurens.vd.oever.nl/weblog/items2005/closures/http://www.jibbering.com/faq/faq_notes/closures.htmlhttp://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closureshttp://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closureshttp://blog.morrisjohns.com/javascript_closures_for_dummies.htmlhttp://www.mollypages.org/misc/jsclo.mp#5http://www.mollypages.org/misc/jsclo.mp#4http://www.mollypages.org/misc/jsclo.mp#3http://www.mollypages.org/misc/jsclo.mp#2http://www.mollypages.org/misc/jsclo.mp#1
  • 8/13/2019 Closures Explainned - Muito Bom

    2/9

    foo(); //=> assigns the inner (anonymous) function toglobal variable bar

    bar(); //=>invokes nested function bar

    function bar

    isnow reachable from outsidefunction foo

    , since it hasbeen assigned to a global variable bar (since bar is not preceded with"var" it is a global variable).

    Note, foo()has to be invokedat least once for global variable barto beset.

    Inner functions can also be returnedfrom the outer function function foo()

    { var bar = function () { } returnbar; } var bar_reference = foo(); bar_reference(); //=>invokes nested function bar

    function barisnow reachable from outside function foo, since it has

    been assigned to a global variable bar_reference.

    Note, foo()has to be invokedat least once for it to return the referenceto bar.

    3. Closures

    As shown above, nested functions can be accessed from outside theouter function. A closure is created the moment a nested functionisdefined and returned (or defined and invoked).

    A closure simply means that the inner function has access to internal

    (local) variables of the outer function.

    The interesting part is that it has access to those local variableseven afterthe outer function has finished executing and no longer

    exists. This is achieved by Javascript internally saving the state of the

    local outer variables in a separate "closure" object.

    function foo(){

  • 8/13/2019 Closures Explainned - Muito Bom

    3/9

    var x = "hello";function bar() {

    alert(x);}

    return bar;}

    var bar_ref= foo();//foo has finished executing at this point and local//variable x does not exist anymore

    bar_ref(); //=> alerts "hello"

    bar_ref()correctly alerts "hello" in this example because the

    variable xis still accessible via the closure.

    Local variables saved in closures are anything declared via the "var"keyword in the outer function andany method parameters of the outerfunction.

    function foo(x) { function bar() { alert(x); } return bar; } var bar_ref = foo("hello"); bar_ref();

    bar_ref()correctly alerts "hello" in this example because the local

    method parameter variable is accessible via the closure.

    Important note: A new closureis created everytime a inner function isassigned or returned.

  • 8/13/2019 Closures Explainned - Muito Bom

    4/9

    function foo(x){function bar() {

    alert(x);}

    return bar;}

    var bar_ref_1 = foo("hello");var bar_ref_2 = foo("world");

    bar_ref_1(); //alerts hellobar_ref_2(); //alerts world

    Note: this means that multiple closures are created by the same nestedfunction (every time the nested function is called) and

    modifying/changing variables contained in one closure cannot affect

    any other closures.

    4. When are closures useful ?

    Closures essentially save us from the need to create global variables.

    They are mostly useful in event handlers/callback functions, when suchfunctions need to access some callback specfic data.

    In Java, we can specify a method as a so-called "callback" function.

    We can create several different objects (each with different instancedata) and can specify a particular object upon which the callback

  • 8/13/2019 Closures Explainned - Muito Bom

    5/9

    method will be invoked. This method, when invoked, will have access

    to its own object data.

    class MyObject {String greeting;

    MyObject(String word) {this.greeting = word;}

    void showGreeting() { System.out.print(greeting); }}

    MyObject obj1 = new MyObject("hello");MyObject obj2 = new MyObject("world");

    SomeEventHandler.addCallBack(obj1); //invokesshowGreeting()and prints "hello"SomeEventHandler2.addCallBack(obj2); //invokesshowGreeting()and prints "world"

    Note, the event handler runs on a different thread (typically awt/swing

    event handler thread) but the method that is invoked has access to it'sown object data (since all methods are tied to objects).

    Alternately, (in Java) it's also common to pass a "this" object pointer toan event handler (when the event handler is added by the object on

    itself) and the event handler can use the "this" pointer to access thatparticular object's data.

    The object passed to the event handler typically implements a interface,such that the event hander (and the compiler) know that the object has a

    well known method that will be called back. (showGreeting()in thisexample).

    By contrast, in Javascript (back in the day, things started out in thisfashion:

    var greeting = "hello";function foo() {

    alert(greeting);}

    SomeElement.addEventHandler("onclick", foo);SomeElement2.addEventHandler("onclick", foo);

    There were event handlers that would invoke global functions (whichcould access only global variables). In this example, we are limited to

    only one value for the greetingvariable, every time it is read

    from foo()(since it is a global variable).

    If we now try and follow the Java model and object-ify things, we cansay:

  • 8/13/2019 Closures Explainned - Muito Bom

    6/9

    function MyObject(word) {

    this.greeting = word;this.handle = function() {

    alert(this.greeting);}

    }

    var obj1 = new MyObject("hello");var obj2 = new MyObject("world");

    SomeElement.addEventHandler("onclick", obj1);SomeElement2.addEventHandler("onclick", obj2);

    This mayor may notwork. It depends on how the callback mechanismis coded:

    1. The callback mechanism could invoke the callback method as afunction. If instead of calling obj1.handle(), the event handlercalls handle(), then 'this' will not point to the right object (it

    will point to the global object, not obj1).

    2. The callback mechanism may not even accept an object, it mayonly accept a function. This is very common in Javascript. For

    example, setTimeoutonly accepts a function.

    3.SomeElement.addEventHandler("onclick", obj1,some_function);

    In this case, it's imposssible to access function specific data

    (unless either a global variable or a closure is used).

    So how do closures solve this problem ?

    function remember_me(word) {function inner() {

    alert(word);}

    return inner;

    }SomeElement.addEventHandler("onclick",remember_me("hello"));

    In this example, the function and associated data ("hello") is

    remembered together, in the form of a closure. The event handler takesa function to a "callback" function (not an object). Yet, the function hasaccess to it's own separate data and each closure-function has

    independent separate data.

    This is conceptually similar to having an method based callback, where

    the method has access to it's object data.

  • 8/13/2019 Closures Explainned - Muito Bom

    7/9

    I feel that closures tend to make things a whole lot more

    complicated and hard to understand in general. They are not really a

    feature in a programming language, just a source of confusion (and inJavascript, sometimes necessary for the above reasons).

    5. Browser specific hacks and bugs

    Internet explorer has some garbage collection bugs. These are not

    closure-specific but are easily exposed when when using closures.

    As shown in the above diagram, IE (version 7 and earlier) has separate

    garbage collectors for native Javascript and HTML DOM that isreflected as Javascript objects.

    If there is a circular link between a HTML DOM object and a nativeobject, then neither is garbage colleted for the duration of the IE

    browser session (even if the user navigates away from the page).

  • 8/13/2019 Closures Explainned - Muito Bom

    8/9

    function addHandler(){var mydiv = document.getElementById("myid");mydiv.onclick = function() {

    alert(this.innerHTML + "\n");}

    In this example, mydiv (in the HTML DOM side) refers to native JScode via its onclickevent handler. The JS code for the event handler,

    refers back to mydiv via the inadvertent closure formed by the inner

    function. This circular reference leaks memory in IE.

    One way around this is to say:

    function addHandler(){var mydiv = document.getElementById("myid");

    mydiv.onclick = handler;}function handler() {

    alert(this.innerHTML + "\n");}

    Since the handlerfunction is not a nested function, no closure isformed.

    Another way to do this without a closure is:

    function addHandler(){var mydiv = document.getElementById("myid");

  • 8/13/2019 Closures Explainned - Muito Bom

    9/9

    mydiv.onclick = new Function('alert(this.innerHTML)');

    }

    Even though the handler function is defined inline, the use of

    the Functionconstructor prevents a implicit closure (functions createdvia a Function constructor do not save local scope).

    Returnto Misc. topics index

    http://www.mollypages.org/misc/index.mphttp://www.mollypages.org/misc/index.mphttp://www.mollypages.org/misc/index.mp