Discussion:
forEach & scope gotcha
Eoghan
2008-12-03 15:18:50 UTC
Permalink
I commonly use forEach within another function, like the following
example:

connect(el, 'onclick', function(e){
var my_var = getNodeAttribute(e.src(), 'someattr');
forEach(getElementsByTagAndClassName('div', 'some_class'),
function(mydiv){
if(getNodeAttribute(mydiv, 'someattr') == my_var){
// do something
}
}
});

Unfortunately 'my_var' takes on unexpected values, because the
function that acts as the body of the forEach is a closure (I think).
Converting the above code to use a plain old 'for' loop acts as
expected:

connect(el, 'onclick', function(e){
var my_var = getNodeAttribute(e.src(), 'someattr');
var arr = getElementsByTagAndClassName('div', 'some_class');
for(var i=0; i<arr.length; i++){
var mydiv = arr[i];
if(getNodeAttribute(mydiv, 'someattr') == my_var){
// do something
}
}
});

Using a partial function for the forEach body with 'my_var'
preinitialised seems clunky to me and definitely reduces readability.
What is the most elegant way to make forEach behave as expected (as
illustrated by the second example)?

Thanks!

Eoghan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Per Cederberg
2008-12-03 18:59:35 UTC
Permalink
To me it seems both version should work equally well. Each function
scope created should be linked together, causing the "my_var" variable
lookup to be found in the outer function when not defined in the local
function scope. Unless I've misunderstood something about variable
scoping in JavaScript.

On the other hand, it looks like you are just filtering elements by
tag name, class and attribute value. Wouldn't it be nice to just use a
selector instead?

connect(el, 'onclick', function (e) {
var my_var = getNodeAttribute(e.src(), 'someattr');
forEach($$("div.some_class[someattr='" + my_var + "']"), function(mydiv) {
// do something
}
});

Cheers,

/Per
Post by Eoghan
I commonly use forEach within another function, like the following
connect(el, 'onclick', function(e){
var my_var = getNodeAttribute(e.src(), 'someattr');
forEach(getElementsByTagAndClassName('div', 'some_class'),
function(mydiv){
if(getNodeAttribute(mydiv, 'someattr') == my_var){
// do something
}
}
});
Unfortunately 'my_var' takes on unexpected values, because the
function that acts as the body of the forEach is a closure (I think).
Converting the above code to use a plain old 'for' loop acts as
connect(el, 'onclick', function(e){
var my_var = getNodeAttribute(e.src(), 'someattr');
var arr = getElementsByTagAndClassName('div', 'some_class');
for(var i=0; i<arr.length; i++){
var mydiv = arr[i];
if(getNodeAttribute(mydiv, 'someattr') == my_var){
// do something
}
}
});
Using a partial function for the forEach body with 'my_var'
preinitialised seems clunky to me and definitely reduces readability.
What is the most elegant way to make forEach behave as expected (as
illustrated by the second example)?
Thanks!
Eoghan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Eoghan
2008-12-08 11:24:56 UTC
Permalink
Thanks for your help Per, I've revisited this and can't recreate the
bug, so I must have reported it incorrectly.
I expect JavaScript scope still works as you understood it!
Also yes, $$ is proving to be a boon vs. getElementsByTagAndClassName
etc.
Post by Per Cederberg
To me it seems both version should work equally well. Each function
scope created should be linked together, causing the "my_var" variable
lookup to be found in the outer function when not defined in the local
function scope. Unless I've misunderstood something about variable
scoping in JavaScript.
On the other hand, it looks like you are just filtering elements by
tag name, class andattributevalue. Wouldn't it be nice to just use aselectorinstead?
  connect(el, 'onclick', function (e) {
      var my_var = getNodeAttribute(e.src(), 'someattr');
      forEach($$("div.some_class[someattr='" + my_var + "']"), function(mydiv) {
          // do something
      }
  });
Cheers,
/Per
Post by Eoghan
I commonly use forEach within another function, like the following
   connect(el, 'onclick', function(e){
       var my_var = getNodeAttribute(e.src(), 'someattr');
       forEach(getElementsByTagAndClassName('div', 'some_class'),
function(mydiv){
           if(getNodeAttribute(mydiv, 'someattr') == my_var){
                // do something
           }
       }
   });
Unfortunately 'my_var' takes on unexpected values, because the
function that acts as the body of the forEach is a closure (I think).
Converting the above code to use a plain old 'for' loop acts as
   connect(el, 'onclick', function(e){
       var my_var = getNodeAttribute(e.src(), 'someattr');
       var arr = getElementsByTagAndClassName('div', 'some_class');
       for(var i=0; i<arr.length; i++){
           var mydiv = arr[i];
           if(getNodeAttribute(mydiv, 'someattr') == my_var){
                // do something
           }
       }
   });
Using a partial function for the forEach body with 'my_var'
preinitialised seems clunky to me and definitely reduces readability.
What is the most elegant way to make forEach behave as expected (as
illustrated by the second example)?
Thanks!
Eoghan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---

Loading...