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.
Results 1 to 4 of 4
  1. #1
    New to the CF scene
    Join Date
    Feb 2013
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Question closures and weird scope chain

    Hi everyone,
    I wrote this piece of code in order to play with DOM objects, closures and function constructors at the same time.

    The problem is that I don't obtain what I expected. The two buttons should show the value of two separates "nrClick" local variables, thinking about the closure created with the declared inner function and its two execution contexts it should have been evaluated because of the two "new DHtmlObject()" I call.

    So.. what's wrong? Why do the two functions refer to the same last local variable nrClick created?

    Code:
    <!--
    
    -->
    <html>
    <head>
    <meta http-equiv="Content-Script-Type" content="text/javascript">
    
    <script>
    
    function associateObjWithEvent(object, methodName){
        var fun= function(e){
            return(object[methodName](e, this));
        }
        
        return fun;
    }
    
    
    function DHtmlObject(elementID){
        var el= document.all[elementID];
        var nrClick= 0;
        
        var f= function(event, element){
                element.value="click " + nrClick++;
            };
            
        if(! DHtmlObject.prototype.doOnClick)
            DHtmlObject.prototype.doOnClick= f;
        
        if(el){
            el.onclick= associateObjWithEvent(this, "doOnClick");
        }
        
        return f;
    }
    
    
    </script>
    
    </head>
    
    <body>
    <form>
    <input id="try1" type="button" value="try me">
    <input id="try2" type="button" value="try me">
    </form>
    <script>
    
    var a= new DHtmlObject("try1");
    var b= new DHtmlObject("try2");
    
    </script>
    </a>
    
    </body>
    </html>

  • #2
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,466
    Thanks
    3
    Thanked 495 Times in 482 Posts
    nrClick is 0 and is the same variable for both objects

    Code:
    <html>
    <head>
    <meta http-equiv="Content-Script-Type" content="text/javascript">
    
    <script>
    
    
    function DHtmlObject(elementID){
        var el= document.all[elementID];
        this.el=el;
        this.cnt=0;
        this.addevt(el,'click','click');
    }
    
    DHtmlObject.prototype={
    
     click:function(){
      this.el.value='Count '+this.cnt++;
     },
    
     addevt:function(o,t,f,p){
      var oop=this;
      if (o.addEventListener){
       o.addEventListener(t,function(e){ return oop[f](e,p);}, false);
      }
      else if (o.attachEvent){
       o.attachEvent('on'+t,function(e){ return oop[f](e,p); });
      }
     }
    
    }
    
    </script>
    
    </head>
    
    <body>
    <form>
    <input id="try1" type="button" value="try me">
    <input id="try2" type="button" value="try me">
    </form>
    <script>
    
    var a= new DHtmlObject("try1");
    var b= new DHtmlObject("try2");
    
    a.click()
    
    </script>
    </a>
    
    </body>
    </html>
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • #3
    New to the CF scene
    Join Date
    Feb 2013
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Smile

    I've found the solution!
    Here is a clearer piece of code that shows the issue:
    Code:
    <!--
    cliccando il link che contiene l'immagine, cambiera' il src (visualizzandolo) ma per un tempo brevissimo, per poi tornare al src originale.
    Qualcuno mi spiega questo comportamento? Cosa sbaglio?
    -->
    <html>
    <head>
    <meta http-equiv="Content-Script-Type" content="text/javascript">
    
    <script>
    var ob1= new Object();
    var ob2= new Object();
    
    function functionToCall(obj, methodName){
        var f= function(){
            return(obj[methodName]());
        }
        
        return(f);
    }
    
    function ScopeChainTry(nameObj){
        var nrCall= 0;
        
        var f= function(){
            document.write("<br>" + nrCall++);
        }
        
        if(ScopeChainTry.prototype.fun == undefined){
            ScopeChainTry.prototype.fun= f;
        }
        
        window[nameObj].actionFun= functionToCall(this,"fun");
    }
    
    var a= new ScopeChainTry("ob1");
    ob1.actionFun();
    ob1.actionFun();
    
    var b= new ScopeChainTry("ob2");
    ob2.actionFun();
    ob1.actionFun();
    
    
    </script>
    
    </head>
    
    <body>
    
    <script>
    </script>
    
    
    </body>
    </html>
    Well, you were right, it is the same variable of course! But I was wondering why.
    The reason is simple: the scopechain related to the function referenced by ScopeChainTry.prototype.fun will be always the same (that function will have a scopechain bind to the execution context of the first "new ScopeChainTry"). That's it


    A solution could be like this (I use the object that the constructor initializes to store variables, not the function object itself):

    Code:
    <!--
    
    -->
    <html>
    <head>
    <meta http-equiv="Content-Script-Type" content="text/javascript">
    
    <script>
    
    function associateObjWithEvent(object, methodName){
        var fun= function(e){
            return(object[methodName](e, this));
        }
        
        return fun;
    }
    
    
    function DHtmlObject(elementID){
        var el= document.all[elementID];
        this.nrClick= 0;
        
        var f= function(event, element){
                element.value="click " + this.nrClick++;
            };
            
        if(! DHtmlObject.prototype.doOnClick)
            DHtmlObject.prototype.doOnClick= f;
        
        if(el){
            el.onclick= associateObjWithEvent(this, "doOnClick");
        }
    }
    </script>
    
    </head>
    
    <body>
    <form>
    <input id="try1" type="button" value="try me">
    <input id="try2" type="button" value="try me">
    </form>
    <script>
    
    var a= new DHtmlObject("try1");
    var b= new DHtmlObject("try2");
    
    
    </script>
    </a>
    
    </body>
    </html>
    Last edited by benacus; 02-23-2013 at 10:39 PM.

  • #4
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,456
    Thanks
    0
    Thanked 632 Times in 622 Posts
    The simplest way to remember it is:

    var nrCall= 0; create a single variable to share between all objects created from this one.

    this.nrCall= 0; create a separate variable for each object created from this one.
    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.


  •  

    Posting Permissions

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