Hi,

> So if I'm inside an anonymous function, can I  
> still use window...

Yes if the functions in question are declared at global scope (as in
Pranav's example), no if they aren't (you can access `window`, but the
functions won't be properties of it).

So this would work:

    function foo() {
    }
    var x = 'foo';
    window[x]();

but this would not:

    function bar() {
        function foo() {
        }
        var x = 'foo';
        window[x](); // fails, no "foo" prop on `window`
    }

The reason it works at global scope (technically, in the global
execution environment) is that the global execution environment has a
unique feature: `var`s and function declarations at global scope end
up as properties on the global object, which is accessible as `window`
in browsers (and accessible in a similar way in non-browser
environments). Although there is (at least conceptually) a similar
object in the second example that has a "foo" property, we have no way
of accessing that object directly.

If you're interested, I've given a very high-level overview of the
details below (there's still a fair bit of hand-waving; the ECMAScript
spec is 252 pages long for a reason).

So, the global execution environment has a unique feature that lets us
get at the variables defined at global scope. Before we can talk about
how that happens, we have to talk about "variable environment" object:

Consider this code (which is at the top level, not in any function):

* * * *
var global = "Hi";

function foo() {
    var fooLocal = "there";

    alert(global); // "Hi"
    alert(typeof bar); // "function"
    alert(typeof barLocal); // "undefined" because it's not in scope

    function nifty() {
        var niftyLocal = "!";

        alert(global + " " + fooLocal + niftyLocal); // "Hi there!"
    }
}

function bar() {
    var barLocal = "flibbergibbet";
}
* * * *

You can think of the above is a bunch of boxes containing boxes:

+-- window -------------------------------+
|                                         |
| +-- foo ------------------------------+ |
| |                                     | |
| | +-- nifty ------------------------+ | |
| | |                                 | | |
| | |                                 | | |
| | +---------------------------------+ | |
| |                                     | |
| +-------------------------------------+ |
|                                         |
| +-- bar ------------------------------+ |
| |                                     | |
| +-------------------------------------+ |
|                                         |
+-----------------------------------------+

Without delving too much into the mechanics of it, when you call `foo`
(for instance), the interpreter creates a "variable environment"
object for the call. This object gets assigned properties for all of
the `var`s in the function, all of the named functions declared within
the function, all of its declared arguments, and the `arguments`
property. So if you call `foo`, its variable object would have these
properties:

- arguments
- fooLocal
- nifty

If you call `nifty`, its variable object would look like this:

- arguments
- niftyLocal

Unqualified references within the function are resolved by looking
them up on the variable object. So within `nifty`, if I refer to
`niftyLocal`, it's found on `nifty`'s variable object. But what if I
refer to `fooLocal`? It's not on `nifty`'s variable object, and so the
interpreter looks for the next variable object in the chain, which is
`foo`'s. And there's `fooLocal`, so we're done. If `nifty` refers to
`global`, it's not found on `nifty`'s variable object, and it's not
found on `foo`'s, so how does it get resolved?

It gets resolved because functions aren't the only things with
variable objects; the master call to the global code that ran the page
also has a variable object, and so the chain continues with that one.
Since that variable object has `global` on it, it's resolved.

E.g., when calling `nifty`, its identifier resolution chain looks like
this:

`nifty`'s variable object
   -> `foo`'s variable object
      -> the global environment's variable object

(It's actually a bit more complicated than that, but the complications
are not relevant here.) I give a marginally better picture in my blog
post here.[1]

Now, these variable objects are anonymous (in fact, in any given
implementation they may just be conceptual, not real). There's no way
to get a reference to the variable object for a given call to `foo`,
it's just not a specified part of the language. (The `arguments`
object gives you a very, very limited view into the variable object,
but that's it.)

EXCEPT! Remember that unique feature of the global execution
environment? Here it is: Its variable object effectively *is* the
global object. And in browsers, the global object has a property
called "window" that it uses to refer to itself. And so we have direct
access to the variable object for the global execution environment,
which makes it unique. (This is all defined by a constellation of
sections in the spec, but the most relevant are 10.4.1 and 10.2.3.)

So when we do this at global scope:

function foo() {
}

...we create a property on the global environment's variable object
called "foo", and since that object effectively is the global object,
and the global object effectively has a name ("window"), we can refer
to it as window["foo"].

But we can't do that to refer to `foo` here:

function bar() {

    function foo() {
    }
}

...because the variable object for the call to `bar` doesn't have a
name and we have no way of accessing it directly.

[1] http://blog.niftysnippets.org/2008/02/closures-are-not-complicated.html

HTH,
--
T.J. Crowder
Independent Software Consultant
tj / crowder software / com
www.crowdersoftware.com


On Apr 14, 10:05 pm, Walter Lee Davis <wa...@wdstudio.com> wrote:
> Yes it does. Thanks. So if I'm inside an anonymous function, can I  
> still use window, or do I need to figure out a scope variable to where  
> I am and use that?
>
> Walter
>
> On Apr 14, 2010, at 4:33 PM, Pranav wrote:
>
>
>
> > Does this help?
>
> > <script type="text/javascript">
> > function foo(){
> >    alert("Meow");
> > }
>
> > function bar(){
> >       alert('Woof woof');
> > }
>
> > var x = 'foo';
> > window[x]();
> > window['bar']();
>
> > </script>
>
> > On Apr 14, 2:52 pm, Walter Lee Davis <wa...@wdstudio.com> wrote:
> >> In PHP, there's this handy construct where you can use the value of a
> >> variable as the name of a function, so when you call $foo() you would
> >> call the real function bar() or baz(), depending on the value of $foo
> >> in the current scope.
>
> >> Is there an equivalent in JavaScript, and if so, what is it? I am
> >> looking at taking the return of an Ajax callback and using it to
> >> decide whether to add or remove a classname from an element.
>
> >> Thanks in advance,
>
> >> Walter
>
> > --
> > You received this message because you are subscribed to the Google  
> > Groups "Prototype & script.aculo.us" group.
> > To post to this group, send email to 
> > prototype-scriptaculous@googlegroups.com
> > .
> > To unsubscribe from this group, send email to 
> > prototype-scriptaculous+unsubscr...@googlegroups.com
> > .
> > For more options, visit this group 
> > athttp://groups.google.com/group/prototype-scriptaculous?hl=en
> > .

-- 
You received this message because you are subscribed to the Google Groups 
"Prototype & script.aculo.us" group.
To post to this group, send email to prototype-scriptacul...@googlegroups.com.
To unsubscribe from this group, send email to 
prototype-scriptaculous+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/prototype-scriptaculous?hl=en.

Reply via email to