Go Back   CodingForums.com > :: Client side development > JavaScript programming

Before you post, read our: Rules & Posting Guidelines

Reply
 
Thread Tools Rate Thread
Enjoy an ad free experience by logging in. Not a member yet? Register.
Old 02-23-2013, 06:32 PM   PM User | #1
benacus
New to the CF scene

 
Join Date: Feb 2013
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
benacus is an unknown quantity at this point
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>
benacus is offline   Reply With Quote
Old 02-23-2013, 08:04 PM   PM User | #2
vwphillips
Senior Coder

 
Join Date: Mar 2005
Location: Portsmouth UK
Posts: 4,379
Thanks: 3
Thanked 466 Times in 453 Posts
vwphillips is a jewel in the roughvwphillips is a jewel in the roughvwphillips is a jewel in the rough
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.uk/

If my post has been useful please donate to http://www.operationsmile.org.uk/
vwphillips is offline   Reply With Quote
Old 02-23-2013, 10:27 PM   PM User | #3
benacus
New to the CF scene

 
Join Date: Feb 2013
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
benacus is an unknown quantity at this point
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..
benacus is offline   Reply With Quote
Old 02-23-2013, 10:43 PM   PM User | #4
felgall
Master Coder

 
felgall's Avatar
 
Join Date: Sep 2005
Location: Sydney, Australia
Posts: 5,530
Thanks: 0
Thanked 503 Times in 494 Posts
felgall is a jewel in the roughfelgall is a jewel in the roughfelgall is a jewel in the rough
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/
felgall is offline   Reply With Quote
Reply

Bookmarks

Jump To Top of Thread


Thread Tools
Rate This Thread
Rate This Thread:

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

Forum Jump


All times are GMT +1. The time now is 12:11 AM.


Advertisement
Log in to turn off these ads.