Closure variable bindings

G

getsanjay.sharma

Hello to all Javascript programmers out there.

Recently I have been fiddling with closures and have come at a stage
where I need to freeze or capture the values of the variables of the
enclosing or the parent function of a closure which I have been
unsuccessful in doing so far.

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>OK</title>
<script type="text/javascript">
function assign(elem, func)
{
elem.onclick = func();
}

//This works incorrectly
function doS()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
assign(arr, function() {
return function() {
alert(i);
};
});
}

//And so does this
function doZ()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
arr.onclick = function() {
alert(i);
}
}

/*
//This works for obvious reasons, but is this the only way?
function doS()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
{
arr.val = i;
arr.onclick = function() {
alert(this.val);
}
}
}
*/
</script>
</head>
<body id="bodyMain" onload="doS();">
<form action="a.html" method="get">
<div>
<input type="text" id="txtId" value="OK" />
<input type="text" name="txtName" value="txtName" />
<input type="button" value="Submit" />
<a href='#'><input type='button' value='OK' /></a>
</div>
</form>
</body>
</html>

Any suggestions / comments / constructive criticisms / code snippets
would be really appreciated along with a bit of theoretical
explanation if possible. :)

Thanks and regards,
STS.
 
V

VK

<script type="text/javascript">
function assign(elem, func)
{
elem.onclick = func();
}

//This works incorrectly
function doS()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
assign(arr, function() {
return function() {
alert(i);
};
});
}

//And so does this
function doZ()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
arr.onclick = function() {
alert(i);
}
}


Please consider it as a strictly my IMHO, but the "might and beauty"
of JavaScript are not hidden neither in anonymous functions nor nested
closures nor sophisticated memory leaks: though many programs are
tending to prove the opposite, especially in the last ingredient :)


<script type="text/javascript">

var MyFactory = new Function(
'arg','return "window.alert("+arg+");";');

var arr = new Array(100);
var len = arr.length;

for (var i=0; i<len; i++) {
arr = new Function(MyFactory(i));
}

arr[0]();
arr[10]();
arr[99]();
</script>
 
G

Geoffrey Summerhayes

Hello to all Javascript programmers out there.

Recently I have been fiddling with closures and have come at a stage
where I need to freeze or capture the values of the variables of the
enclosing or the parent function of a closure which I have been
unsuccessful in doing so far.

Closures capture the variable not the value. When
you refer to it later you get its current value,
not the value when the closure was created.

For example:

function foo()
{
var balance=0;
return {getBalance:function(){return balance},
deposit:function(x){balance+=x},
withdraw:function(x){balance-=x}}
}

var bar = foo(),baz=foo();
bar.deposit(200);
baz.deposit(200);
bar.withdraw(100);
baz.deposit(100);

bar.getBalance() gives 100
baz.getBalance() gives 300
bar.balance is undefined

Note that foo() was called twice and
a new variable binding for balance
was created each time. That is to
say bar's getBalance, deposit, and
withdraw are all closing over the
same balance, but baz's close over a
different one.

Try:

function doS()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
assign( arr,
// creates a new variable x
// hence a different binding
// every iteration
function(x)
{
return function()
{
alert('x:'+x+',i:'+i)
}
}(i)
);
}
 
R

RobG

<script type="text/javascript">
function assign(elem, func)
{
elem.onclick = func();
}
//This works incorrectly
function doS()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
assign(arr, function() {
return function() {
alert(i);
};
});
}

//And so does this
function doZ()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
arr.onclick = function() {
alert(i);
}
}


Please consider it as a strictly my IMHO, but the "might and beauty"
of JavaScript are not hidden neither in anonymous functions nor nested
closures nor sophisticated memory leaks: though many programs are
tending to prove the opposite, especially in the last ingredient :)

<script type="text/javascript">

var MyFactory = new Function(
'arg','return "window.alert("+arg+");";');


It is code like that that makes me realise why some feel using the
Function object as a constructor is little better than eval.

var arr = new Array(100);
var len = arr.length;

for (var i=0; i<len; i++) {
arr = new Function(MyFactory(i));


In this case, why not:

arr = new Function('alert(' + i + ')');


There are other approaches:

arr = (function(i){
return function(){alert(i)}
})(i);


or the equivalent:

for (var i=0; i<len; i++) {
arr = addFn(i);
}

function addFn(i){
return function(){alert(i)}
}
 
R

RobG

Hello to all Javascript programmers out there.

Recently I have been fiddling with closures and have come at a stage
where I need to freeze or capture the values of the variables of the
enclosing or the parent function of a closure which I have been
unsuccessful in doing so far.
[... refrain from comment about XHTML ...]
<script type="text/javascript">
function assign(elem, func)
{
elem.onclick = func();
}

//This works incorrectly

Maybe it works, but it is also convoluted. You pass a function that
must be executed in order to assign a function, I guess in an attempt
to break the closure involving doS.

function doS()
{
var arr = document.getElementsByTagName('input');
for(var i = 0, max = arr.length; i < max; ++i)
assign(arr, function() {
return function() {
alert(i);
};
});


Try:

for(var i = 0, max = arr.length; i < max; ++i) {
arr.onclick = (function(i){
return function() { alert(i); };
})(i);
}


There are other ways to break the closure, see my response to VKs
post. e.g.:

function assign(arg) {
return function(){alert(arg)};
}

function doS() {
var arr = document.getElementsByTagName('input');
for(var i=0, max=arr.length; i < max; ++i) {
arr.onclick = assign(i);
}
}

which is really just another way of writing the first method, but
allows the declaration of the attached function to occur outside the
function that is assigning it.
 
V

VK

Please consider it as a strictly my IMHO, but the "might and beauty"
It is code like that that makes me realise why some feel using the
Function object as a constructor is little better than eval.

<< IMHO
It is code like the originally posted makes me realize why a subtle
200-300Kb JavaScript program may easily make a 300Mz junk out of my
3Gz machine :)
Nothing personally against of OP, I am talking about the whole
currently prevailing pseudo-OOP anankastic programming pattern of big
JavaScript libraries - I would say "commercial libraries" if they
wouldn't be free of charge.
IMHO

var arr = new Array(100);
var len = arr.length;
for (var i=0; i<len; i++) {
arr = new Function(MyFactory(i));


In this case, why not:

arr = new Function('alert(' + i + ')');


Because I did not want to scare anyone with too of simplicity right
away :) The current pattern - see atop - requires at least 2-4
unnecessary forwarding calls between functions and at the very least
two cross-breaded closures per object instance for a sufficient memory
leak. By making everything too simple I would make the code too much
of "visually unacceptable" :)

After all the approach itself is totally alien to me, as it creates N
identical methods for each instance instead of one static shared by
all instances as it used to be. And one doesn't keep states of
methods, one has current _properties_ of each object used in the same
(static) method. But OK, let's say I understand in OOP like a pig in
apples. Whoever came to the same conclusion - he may save on
posting :)
There are other approaches:

arr = (function(i){
return function(){alert(i)}
})(i);

or the equivalent:

for (var i=0; i<len; i++) {
arr = addFn(i);
}

function addFn(i){
return function(){alert(i)}
}
 
G

getsanjay.sharma

On Nov 15, 2:13 pm, (e-mail address removed) wrote:

Closures capture the variable not the value. When
you refer to it later you get its current value,
not the value when the closure was created.
It seems strange that the closures only capture the variables and not
their snapshots at the time the function declaration is encountered,
but I guess it has got something to do with the theory of closures or
the complexity of the implementation.

So I guess the only thing I was missing was the function invocation
which would have bound the variable as I needed. Nice.

Thanks and lot to everyone who contributed on this thread for their
patient and enlightening replies. :)

Regards,
~/STS
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,818
Latest member
Brigette36

Latest Threads

Top