Go Back   SitePoint Forums > Forum Index > Program Your Site > JavaScript
Newsletter FAQ Members List Calendar Mark Forums Read

New to SitePoint Forums? Register here for free!

SitePoint Sponsor
 
Reply
 
Thread Tools Display Modes
Old Nov 8, 2009, 09:47   #1
RLM2008
SitePoint Enthusiast
 
RLM2008's Avatar
 
Join Date: Nov 2008
Location: Thailand
Posts: 74
Clarification on closures?

Hi,

Trying slowly but surely to get to grips with closures. My question really is regarding the differences between function declaration and invocation.

If I look at Example 1(below), it seems to me that when the function is called the Closure1 inner function is only be declared at that time. Rather than invoked.

From what I've read when an inner function is declared a function object is created and it is given the scope of the context in which it is declared i.e. in this case Example1.

So does that mean the scope chain is assigned to it's scope property, and that the scope chain points to the Example1's activation/variable object? Does it also mean that because of this reference Example1's activation object is saved from garbage collection?

I think my real question is about the preservation of the outer function's variables. In this regard does it make a difference whether an inner function is invoked or declared? It seems to me the answer is no.

Additionally I've tried to breakdown the script example with comments at the bottom. If my understanding is way off I would love to know.

Hopefully I'm not talking too much nonsense here. Would like to be 100% on this.

Thanks

RLM

Java Code:
// ------------- Closure Example 1
function Example1(){
    var a=[];
    for (var num=0; num<10;num++){
        a[num] = function(){// Closure1
            return num;
            };
        }
    return a;
}
// ------------- Closure Example 2
function Example2(){
    var a = [];
    for (var num=0; num<10;num++){
        a[num] = (function(numVal){// Closure 1
                    return function(){// Closure 2
                        return numVal;
                    }
                })(num);
       }
   return a;
}
newArray = Example1();
newArray2 = Example2();
for (x=0; x<10; x++){
    console.log ('Example1 : '+newArray[x]()+'   Example2 : '+newArray2[x]());
    }
 
    // Output
    // Example1: 10  Example2 : 0
    // Example1: 10  Example2 : 1
    // Example1: 10  Example2 : 2
    // ...
    // Example1: 10  Example2 : 9
 
// Example 1
// Closure 1 returns a reference to the variable num. The reference to num comes from the outer function Example1.
// Due to the fact it's a reference any changes made to num in the outer function during it's execution will be
// reflected in Closure1's referenced variable. That's why the functions in array 'a' return the last value of num, which is 10.
 
// Example 2
// To overcome the problem of Example 1 we pass the value of num directly into the inner function Closure1.
// The value is passed as the named argument numVal.
// The innermost function Closure2 which is returned, holds a reference to numVal.
// Each time Closure 1 is called a new and separate numVal argument is created.
// Therefore equally the returned numVal reference from Closure 2 is a different reference each time.
RLM2008 is offline   Reply With Quote
Old Nov 9, 2009, 09:03   #2
PhilipToop
SitePoint Enthusiast
 
Join Date: Jun 2007
Location: North Yorkshire, UK
Posts: 38
What a complex question just trying to get my head around it.

As far as Example 1 is concerned. I believe each element of the array is a function, the same code but essentially a different function. When the assignment is done then you are declaring the function. Only when the array element is used does the function is executed. The function returns the current value of the variable num. Normally, num would be just local to that loop but the function is effectively part of the loop.

In example 2 I believe your are declaring a function with a argument numVal and at the same time invoking in because of the bracketing with an argument (num). That function returns the internal function (Closure 2). This time Closure 2 references the numVal argument. Since the outer function is called on each iteration of the loop the inner function will reference the value at that time. As with example 1 each element of the array is a function, the code might be same but the local variables are different.

Sorry if this is saying the same as you but in different words.
PhilipToop is online now   Reply With Quote
Old Nov 9, 2009, 09:38   #3
crmalibu
SitePoint Wizard
 
Join Date: Jul 2008
Posts: 4,767
You're on the right track, but let me emphasize something. The point is that you're creating a copy of the value. This is because the number is a primitive type, not a reference type, and calling a function with a primitive type as one of its arguments, will create a copy of that arguments value.
crmalibu is online now   Reply With Quote
Old Nov 9, 2009, 15:21   #4
PhilipToop
SitePoint Enthusiast
 
Join Date: Jun 2007
Location: North Yorkshire, UK
Posts: 38
Any function is made up of code and local data. In the example 1 they is just code; the only piece of data isn't local to the function. In Example 2 there is both code and data, in that the arguments of the function call are the data. Each array element will have the same code but different data.

This might we seen more easily if Example 2 had been

Code:
function Example2(){
    var a = [];
    for (var num=0; num<10;num++){
        a[num] = (function(numVal){// Closure 1
                       var mynum = numVal;  
                  return function(){// Closure 2
                        return mynum;
                    }
                })(num);
       }
   return a;
}
The effect is the same as the original. Each array element will have its own data and thus its own mynum.

I haven't check this out - so please correct me if I am wrong.
PhilipToop is online now   Reply With Quote
Old Nov 10, 2009, 03:20   #5
RLM2008
SitePoint Enthusiast
 
RLM2008's Avatar
 
Join Date: Nov 2008
Location: Thailand
Posts: 74
Philip thanks for the help, really appreciated. Will have to give it a bit more thought though regarding your 'data' and 'code' explanation. There's so many terms associated with functions and there invocation/declaration that it's a bit hard to keep track.

crmalibu, that makes sense. Thank you. Therefore we get a different copy for each iteration of the loop. This would be a different story had we passed a reference type as an argument instead.

Am I still right in saying that the inner most closure creates references to these copies? In that it looks up numVal in it's own scope, doesn't find it then has to reference it from next along the chain closure1?

Thanks

RLM
RLM2008 is offline   Reply With Quote
Old Nov 10, 2009, 08:25   #6
crmalibu
SitePoint Wizard
 
Join Date: Jul 2008
Posts: 4,767
Quote:
Originally Posted by RLM2008 View Post
Am I still right in saying that the inner most closure creates references to these copies? In that it looks up numVal in it's own scope, doesn't find it then has to reference it from next along the chain closure1?
Yup.
crmalibu is online now   Reply With Quote
Reply

Bookmarks

« Previous Thread | Next Thread »

Thread Tools
Display Modes

 
Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Sponsored Links
 
Forum Jump


All times are GMT -7. The time now is 09:22.


Powered by vBulletin® Version 3.7.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Copyright 1998-2009, SitePoint Pty Ltd. All Rights Reserved