Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
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 chanting in the Monastery: (7)
As of 2024-04-18 07:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found