Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 2 12 LastLast
Results 1 to 15 of 20
  1. #1
    New to the CF scene
    Join Date
    Sep 2013
    Posts
    9
    Thanks
    3
    Thanked 0 Times in 0 Posts

    Question About Scope and Closures

    I've done a lot of reading on the topic of scope and closures and feel that I pretty much understand how it works. But there's a couple of sentences in the textbook Javascript: The Definitive Guide which I keep coming back to as they seem to contradict one another. Under the heading of Closures, one sentence reads:
    Like most modern programming languages, JavaScript uses lexical scoping. This means that functions are executed using the variable scope that was in effect when they were defined, not the variable scope that is in effect when they are invoked.
    Then:
    Closures become interesting when they are invoked under a different scope chain than the one that was in effect when they were defined.
    My confusion is with the first of those 2 quotes. The 2nd quote makes sense and is consistent with everything I have read about scope, execution contexts and identifier resolution.

    Is it possible that the author has chosen his words poorly, because my understanding is that functions are executed with the variable scope which is in effect when the function is invoked. Especially if the execution context is changed using func.Call or func.Apply.

    Am I missing something?

  • #2
    Senior Coder
    Join Date
    Dec 2010
    Posts
    2,391
    Thanks
    11
    Thanked 568 Times in 561 Posts
    No, you are absolutely correct. Functions are executed with the variable scope which is in effect when the function is invoked (not when it was defined).

    Example:
    Code:
    for(i=1; i<11; i++) {
       window.setTimeout(function() {
          console.log(i);
       }, i*100);
    }
    In that case, there will be console outputs after 100ms, 200ms, .... 1000ms. Each of the outputs will be 11, which is the value of i at execution time (after the loop finished). If the value would be the one of definition time, you'd have expected to get 1, 2, 3, .... 10

  • Users who have thanked devnull69 for this post:

    onefootswill (10-31-2013)

  • #3
    New to the CF scene
    Join Date
    Sep 2013
    Posts
    9
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Thanks devnull69.
    I think the author must have just chosen his words poorly.

  • #4
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,277
    Thanks
    10
    Thanked 581 Times in 562 Posts
    Quote Originally Posted by onefootswill View Post
    Is it possible that the author has chosen his words poorly, because my understanding is that functions are executed with the variable scope which is in effect when the function is invoked. Especially if the execution context is changed using func.Call or func.Apply.

    Am I missing something?
    the author is correct and his words are not poor at all, they are descriptive.

    consider a simple proof:

    Code:
    var b=(function(){
      var a=1;
       return function(){return a;} 
    }());
    
    
    function test(){
       var a=99;
      return b();
    }
    
    alert(test());

    if the scope was local at execution, we would see "99" popup, but instead we see "1", the "a" that was local at time of function creation.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/5/28) IE7:0.1, IE8:5.3, IE11:8.4, IE9:3.2, IE10:3.2, FF:18.2, CH:46, SF:7.9, NON-MOUSE:32%

  • #5
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,277
    Thanks
    10
    Thanked 581 Times in 562 Posts
    Quote Originally Posted by devnull69 View Post
    No, you are absolutely correct. Functions are executed with the variable scope which is in effect when the function is invoked (not when it was defined).

    Example:
    Code:
    for(i=1; i<11; i++) {
       window.setTimeout(function() {
          console.log(i);
       }, i*100);
    }
    In that case, there will be console outputs after 100ms, 200ms, .... 1000ms. Each of the outputs will be 11, which is the value of i at execution time (after the loop finished). If the value would be the one of definition time, you'd have expected to get 1, 2, 3, .... 10
    wrong. closure closes names, not values. you aren't closing a value, you are closing a name and when that name is assessed, the value is 11. closure means that i is not undefined, it doesn't mean that the value is sealed in at definition time.

    unless you had a private "i" (heh), the same "i" is being closed by all functions, and it's value is constantly changing until the end of the dispatches. in this case, you are simply pointing to a global. that's why you would have to use an inner function wrap to seal in "i" at the time of definition to have each one different:


    Code:
    for(i=1; i<11; i++) { (function(i){
       window.setTimeout(function() {
          console.log(i);
       }, i*100);
      }(i));
    }
    there we see how it really is definition time that matters, and with that we see 1-10 as expected instead of a bunch of 11s...
    these functions aren't being executed any different, the timeouts are staggered on both, but it's only with the extra function definition that the closure works in a useful way.
    Last edited by rnd me; 10-31-2013 at 06:20 PM.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/5/28) IE7:0.1, IE8:5.3, IE11:8.4, IE9:3.2, IE10:3.2, FF:18.2, CH:46, SF:7.9, NON-MOUSE:32%

  • #6
    New to the CF scene
    Join Date
    Sep 2013
    Posts
    9
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Ahhh. OK. So, with regards to the closure by way of the self-invoking function, I just want to see if I can set out the reason that works.

    1st observation - a separate execution context is created for each function passed to the setTimeout method.

    2nd observation - because the function actually executes, not only is i bound to a variable, but the value at the time of execution is assigned to that variable.

    3rd observation - each execution context which is created contains a reference to the scope chain that exists for that function during each iteration of the for loop. That is closed over as there is an external reference to each function via window.setTimeout

    Have I got that correct?

  • #7
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,277
    Thanks
    10
    Thanked 581 Times in 562 Posts
    Quote Originally Posted by onefootswill View Post
    Ahhh. OK. So, with regards to the closure by way of the self-invoking function, I just want to see if I can set out the reason that works.

    1st observation - a separate execution context is created for each function passed to the setTimeout method.

    2nd observation - because the function actually executes, not only is i bound to a variable, but the value at the time of execution is assigned to that variable.

    3rd observation - each execution context which is created contains a reference to the scope chain that exists for that function during each iteration of the for loop. That is closed over as there is an external reference to each function via window.setTimeout

    Have I got that correct?

    1. yes. it's the private local context of the wrapper function as it execute.


    2. maybe, not sure which function and execution to which you refer.

    let's re-label this to make it clearer what's happening. (this doesn't affect operation at all)

    Code:
    for(i=1; i<11; i++) { (function X(n){
       window.setTimeout(function Y() {
          console.log(n);
       },n * 100);
      }( i ));
    }

    the X's "n" argument is bound by Y at loop time, and the value of X's "n" argument at the time Y fires is given to console.log().

    3. setTimeout provides no external references afaik, but it does leave the call on the heap/stack/event loop to execute later.

    the only things can can be seen at call time by a function are globals and sibling locals of the defining program (function code or a script file code).
    Last edited by rnd me; 11-01-2013 at 03:05 AM.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/5/28) IE7:0.1, IE8:5.3, IE11:8.4, IE9:3.2, IE10:3.2, FF:18.2, CH:46, SF:7.9, NON-MOUSE:32%

  • Users who have thanked rnd me for this post:

    onefootswill (11-01-2013)

  • #8
    New to the CF scene
    Join Date
    Sep 2013
    Posts
    9
    Thanks
    3
    Thanked 0 Times in 0 Posts
    1 & 2 cool.

    Regarding 3, I thought the Global object (window) would have an external reference to the Y function by virtue of the fact that setTimeout is called as a method of the window object.

    If not, then I'll happily accept your explanation that it is left on the heap/stack/event loop to execute later.

  • #9
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,277
    Thanks
    10
    Thanked 581 Times in 562 Posts
    Quote Originally Posted by onefootswill View Post
    1 & 2 cool.

    Regarding 3, I thought the Global object (window) would have an external reference to the Y function by virtue of the fact that setTimeout is called as a method of the window object.
    the browser might have a reference internally, in fact it has to somehow, but there's no way to reach the function(s) Y from JS code.

    the closest you can some is to grab the number that setTimeout returns, which allows you to cancel the timeout, but not reach the code within the timeout afaik.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/5/28) IE7:0.1, IE8:5.3, IE11:8.4, IE9:3.2, IE10:3.2, FF:18.2, CH:46, SF:7.9, NON-MOUSE:32%

  • #10
    New to the CF scene
    Join Date
    Sep 2013
    Posts
    9
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Ah yes. That makes perfect sense. You cannot actually reach it using js.

    Thanks Heaps! I am now much more enlightened!

  • #11
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,592
    Thanks
    0
    Thanked 645 Times in 635 Posts
    Quote Originally Posted by rnd me View Post
    3. setTimeout provides no external references afaik, but it does leave the call on the heap/stack/event loop to execute later.
    You can resolve that by binding setTimeout to a different object instead of window.

    For example:

    Code:
    mytime = function() {
      this.myproperty = 'me';
    }
    
    mytime.prototype.go = function() {
      setTimeout( this.onesecond.bind( this ), 1000 );
    };
    
    mytime.prototype.onesecond = function() {
      alert(this.myproperty);
    };
    Now the execution of the setTimeout is in the scope set when the mytime object was defined and so has access to all the properties and methods of that object.

    The scope of the function called by the setTimeout is that which existed at the time the setTimeout was triggered.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #12
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,277
    Thanks
    10
    Thanked 581 Times in 562 Posts
    Quote Originally Posted by felgall View Post
    You can resolve that by binding setTimeout to a different object instead of window.

    For example:

    Code:
    mytime = function() {
      this.myproperty = 'me';
    }
    
    mytime.prototype.go = function() {
      setTimeout( this.onesecond.bind( this ), 1000 );
    };
    
    mytime.prototype.onesecond = function() {
      alert(this.myproperty);
    };
    Now the execution of the setTimeout is in the scope set when the mytime object was defined and so has access to all the properties and methods of that object.

    The scope of the function called by the setTimeout is that which existed at the time the setTimeout was triggered.
    that's not scope, that's this, which is different. and besides, that doesn't address my point you quoted that the deferred code is unreachable. i'm not saying the closure or this binding doesn't work, i'm saying that once something is passed to setTimeout, there's no way to tell what was passed, other than perhaps looking for side-effects after the callback executes.


    going by this thread, there seems to be much confusion on the topic.
    i'll admit i've made my fair share of assumptions over the years about when stuff is actualized, and JS is a bit different than other languages in this regard.



    I strongly recommend watching this short and good presentation on the topic of function, scope, closure, and this:

    http://www.youtube.com/watch?v=iSxNCYcPAFk#t=205
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/5/28) IE7:0.1, IE8:5.3, IE11:8.4, IE9:3.2, IE10:3.2, FF:18.2, CH:46, SF:7.9, NON-MOUSE:32%

  • #13
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,592
    Thanks
    0
    Thanked 645 Times in 635 Posts
    Quote Originally Posted by rnd me View Post
    that's not scope, that's this, which is different.
    The code in my example changes the scope in which the function called by the setTimeout from window to mytime. You can change the scope of a function from that where it was defined by using call() apply() or bind(). It is only using 'this' to define the new scope - if this and scope were n't different then the code would be meaningless.

    Using the code in my example it would be possible to test for what value that the function the setTimeout is going to call before the setTimeout runs because it is defined in the myTime object and not inside of the setTimout itself.
    Last edited by felgall; 11-03-2013 at 08:53 PM.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #14
    New to the CF scene
    Join Date
    Sep 2013
    Posts
    9
    Thanks
    3
    Thanked 0 Times in 0 Posts
    I still can't get past the distinction between
    when they were defined, and
    not the variable scope that is in effect when they are invoked

    Is there an example someone can give which shows a variable scope that is the scope at the time of invocation, and which is different to the scope at definition.

    rnd_me's example with the self-invoking 'b' function came close. But upon my examination of it, the scope at time of definition is the exact same as the scope at the time of invocation i.e. var i=1. The var a=99 expression is in neither of those scopes. It is in the scope-chain, but that's all.

  • #15
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,277
    Thanks
    10
    Thanked 581 Times in 562 Posts
    Quote Originally Posted by onefootswill View Post
    I still can't get past the distinction between
    when they were defined, and
    not the variable scope that is in effect when they are invoked

    Is there an example someone can give which shows a variable scope that is the scope at the time of invocation, and which is different to the scope at definition.
    .
    did you watch the video?
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/5/28) IE7:0.1, IE8:5.3, IE11:8.4, IE9:3.2, IE10:3.2, FF:18.2, CH:46, SF:7.9, NON-MOUSE:32%


  •  
    Page 1 of 2 12 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •