Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

"When closures capture their context" and "scope gotchas in Javascript"

by clinton (Priest)
on Feb 08, 2008 at 15:41 UTC ( [id://666994]=perlmeditation: print w/replies, xml ) Need Help??

I had this idea that, as soon as you made a closure, all the variables were neatly packaged up and were immutable outside of the closure itself. Then I saw some weird behaviour in Javascript, and investigated further.

Turns out that my assumption was just plain wrong. For instance:

test.pl: ---------------------------------------------- sub say_hello { my $name = shift; my $text = 'Hello '.$name; my $sayAlert = sub { print "$text\n" }; $text = "Not in Perl you don't"; $sayAlert->(); } say_hello('Bob'); ---------------------------------------------- > perl test.pl Not in Perl you don't
Now, reading that again, it makes sense that I would still have access to the variable in the closure from the same scope in which it was declared. So understandably, this version will work as I originally expected:
test.pl: ---------------------------------------------- sub say_hello { my $name = shift; my $sayAlert; { my $text = 'Hello '.$name; $sayAlert = sub { print "$text\n" }; } my $text = "Not in Perl you don't"; $sayAlert->(); } say_hello('Bob'); ---------------------------------------------- > perl test.pl Hello Bob

However, try the same thing in Javascript, and it doesn't work:

function sayHello(name) { var sayAlert; { var text = 'Hello ' + name; sayAlert = function() { alert(text); } } var text='How confused am I?'; sayAlert(); } sayHello('Bob'); ---> "How confused am I?"

It turns out that, unlike Perl, creating a new (nested) block in JS does NOT create a new scope. Instead a new scope is created when a function is declared. Oh, and it doesn't give you any "variable text redefined" warnings either.

Replies are listed 'Best First'.
Re: "When closures capture their context" and "scope gotchas in Javascript"
by moritz (Cardinal) on Feb 08, 2008 at 16:25 UTC
    If you want a new scope in javascript, you can achieve that with an anonymous function that you execute immediately.
    // untested! function sayHello(name){ var sayAlert; var newScope = function() { var text = 'Hello' + name; sayAlert = function() { alert(text) } } newScope(); var text = 'How confused am I?'; sayAlert(); }

    And that's why you want to program in perl, not in javascript (wherever possible).

      Thanks moritz. Actually, I solved my JS problem by just declaring two different variables, instead of reusing the same variable:
      function sayHello(name) { var sayAlert; var text = 'Hello ' + name; sayAlert = function() { alert(text); } var new_text='How confused am I?'; sayAlert(); } sayHello('Bob');

      Not a terribly meaningful example because I don't actually USE new_text, but...

      Perl++ for DWIM!

      You actually do not need to give the function a name:

      (function(){alert('Gotcha')})();
      or in your case:
      function sayHello(name){ var sayAlert; (function() { var text = 'Hello' + name; sayAlert = function() { alert(text) } })(); var text = 'How confused am I?'; sayAlert(); }

Re: "When closures capture their context" and "scope gotchas in Javascript"
by kyle (Abbot) on Feb 08, 2008 at 16:43 UTC

    This kind of scoping is why I swore off PHP too. I wrote quite a bit of code thinking I'd figure out how scoping rules worked later (I figured there must be a my I hadn't found out about yet). It turned out, though, that there were only three scopes: global, file, and function. I was horrified. It's been over a year, and I still cringe a little inside as I think about it.

      Speaking of other language woes - I intended to learn Lua, until I found out that variables are global by default, and you have to add a keyword to limit their scope to the current sub/method.

      That, and the fact that I couldn't find a use strict; equivalent made me jump back to perl immediately.

        Which happens to be the reason both tye and I have relegated Ruby to the "Neat Toy" category. If the compiler can't be enlisted to help you catch typos, then your language design is seriously flawed. (That and how does a language by a Japanese hacker go through 3 versions before an American adds support for UTF-8??)

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
        I intended to learn Lua, until I found out that variables are global by default, and you have to add a keyword to limit their scope to the current sub/method.
        That's true in Perl too if you don't use strict. Well, so in Perl the alternative is lexical scope which, as I know from certain other *ahem*VB*ahem* experience, is much better than subroutine scope for most purposes.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://666994]
Approved by kyle
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (2)
As of 2024-04-20 01:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found