[Chapter 11] 11.5 The JavaScript Name Space
Author: David Flanagan
Date: Fri Aug 29 10:58:16 1997

#

| Chapter 11 Windows and the JavaScript Name Space |

## 11.5 The JavaScript Name Space

We've said that the Window object is really the most central one in client-side JavaScript. This is because it is the object that defines the name space of a program. We saw earlier that every JavaScript expression implicitly refers to the current window. This includes expressions as simple as `window`, which is a reference to a property within the current window that happens to refer to that window itself.

But if every expression refers to the current window, then so does code like this:

    var i;  // declare a variable i
    i = 0;  // assign the variable a value

The assignment `i = 0` is actually the same as writing

    window.i = 0;

This is an important point to understand about client-side JavaScript: variables are nothing more than properties of the current window. (This is not true for local variables declared within a function, however.)

One implication of the fact that variables are properties of the current Window object is that two variables with the same name may be declared in different windows or different frames, and they will not overwrite or conflict with each other.

Another implication is that JavaScript code running in one window or frame may read and write variables declared by code in another window or frame, as long as the first window knows how to refer to the second window.[2] So, if a top-level window has two frames, and code in the first frame does the following:

    parent.frames[1].i = 3;

it is equivalent to code in the second frame doing the following:

    i = 3;

> [2] See Chapter 20, JavaScript Security, however, for a discussion of a "security hobble" that prevents scripts from one web server from reading values from windows that contain data from other web servers.

The final implication of the equivalence between variables and window properties is that there is no such thing as a "global variable" in client-side JavaScript--i.e., there are no user-created variables that are global to Navigator as a whole, across all windows and frames. Each variable is defined only within one window.

Recall that the `function` keyword that defines functions declares a variable just like the `var` keyword does. Since functions are referred to by variables, they to are defined only within the window in which they are declared. That is, if you define a function in one window, you cannot use it in another, unless you explicitly assign the function to a variable in the other window.

Remember that constructors are also functions, so when you define a class of objects with a constructor function and an associated prototype object, that class is only defined for a single window. (See Chapter 7, Objects, for details on constructor functions and prototype objects.) This is true of predefined constructors as well as constructors you define yourself. The String constructor is available in all windows, but that is because all windows automatically are given a property that refers to this predefined constructor function. Just as each window has its own separate reference to the constructor, each window has a separate copy of the prototype object for a constructor. So if you write a new method for manipulating JavaScript strings, and make it a method of the String class by assigning it to the `String.prototype` object in the current window, then all strings in that window will be able to use the new method. But the new method will not be accessible to strings defined in other windows.

Bear in mind that this discussion of variables and Window object properties does not apply to variables declared within functions. These "local" variables exist only within the function body and are not accessible outside of the function. Also, note that there is one difference between variables and properties of the current window. This difference is revealed in the behavior of the `for/in` loop. Window properties that were created by variable declarations are not returned by the `for/in` loop, while "regular" properties of the Window are. See Chapter 5, Statements, for details.

### Variable Scope

We saw above that top-level variables are implemented as properties of the current window or frame object. In Chapter 6, Functions, we saw that local variables in a function are implemented as transient properties of the function object itself. From these facts, we can begin to understand variable scoping in JavaScript; we can begin to see how variable names are looked up.

Suppose a function `f` uses the identifier `x` in an expression. In order to evaluate the expression, JavaScript must look up the value of this identifier. To do so, it first checks if `f` itself has a property named `x`. If so, the value of that property is used; it is an argument, local variable, or static variable assigned to the function. If `f` does not have a property named `x`, then JavaScript next checks to see if the window that `f` is defined in has a property named `x`, and, if so, it uses the value of that property. In this case `x` would be a top-level or "global" (to that window) variable. Note that JavaScript looks up `x` in the window in which `f` was defined, which may not be the same as the window that is executing the script that called `f`. This is a subtle but important difference that can arise in some circumstances.

A similar process occurs if the function `f` uses `document.title` in an expression. In order to evaluate `document.title`, JavaScript must first evaluate `document`. It does this in the same way it evaluated `x`. First it sees if `f` has a property named `document`. If not, it checks whether its Window object has such a property. Once it has obtained a value for `document`, it proceeds to look up `title` as a property that object--it does not check the properties of the function or window, in this case, of course. In this example, the code probably refers to the `document` property of the Window object, and if the function inadvertently defined a local variable named `document`, the `document.title` expression might well be evaluated incorrectly.

What we learn from these examples is that identifiers are evaluated in two scopes: the current function, and the window in which the function is defined. In Chapter 5, Statements we saw that the `with` statement can be used to add additional scopes. When an identifier is evaluated, it is first looked up in the scopes specified by any containing `with` statements. For example, if a top-level script runs the following code:

    with(o) {
      document.write(x);
    }

Then the identifier `x` is evaluated first in the scope of the object `o`. If no definition is found in that object's properties, then `x` is evaluated in the context of the current window. If the same code occurred within a function `f` then `x` would be looked up first as a property of `o`, then as a property of `f` and finally as a property of the current window.

Recall that `with` statements can be nested arbitrarily, creating a variable "scope" of any depth. One interesting way to use `with` is with a window reference:

    with(parent.frames[1]) {
       ...
    }

This technique allows code in one window to easily read properties of another window. Another technique that is sometimes of interest is to place the entire body of a function within the block of a `with(this)` statement. What this does is create a method that evaluates identifiers by looking them up first as properties of the object that it is a method of. Note, however, that such a method would find properties of its object before it found its own local variables and arguments, which is unusual behavior!

#### Scope of event handlers

Event handlers are scoped differently than regular functions are. Consider the `onChange()` event handler of a text input field named `t` within an HTML form named `f`. If this event handler wants to evaluate the identifier `x`, it first uses the scope of any `with` statements of course, and then looks at local variables and arguments, as we saw above. If the event handler were a standalone function, it would look in the scope of the containing window next and stop there. But because this function is an event handler, it next looks in the scope of the text input element `t`. If the property `x` is not defined there, it looks at the properties of the form object `f`. If `f` does not have a property named `x`, JavaScript next checks to see if the Document object that contains the form has a definition of this property. Finally, if no definition of `x` is found in any of these objects, the containing window is checked.

If all identifiers had unique names, scope would never matter. But identifiers are not always unique, and we have to pay attention to scope. One important case is the `Window.open()` method and the `Document.open()` method. If a top-level script of a regular function calls `open()`, JavaScript's scoping rules will find the `open` property of the Window object and use this method. On the other hand, if an event handler calls `open()`, the scoping rules are different, and JavaScript will find the definition of `open` in the Document object before it finds it in the Window object. The same code may work in different ways depending on its context. The moral of this particular example is to never use the `open()` method without explicitly specifying whether you mean `document.open()` or `window.open()`. Be similarly cautious when using `location`; it, too, is a property of both the Window and Document objects.

Finally, note that if an event handler doesn't call `open()` directly but instead calls a function that calls `open()`, the function does not inherit the scope of the event handler that invoked it. The function's scope would be the function itself, and then the window that contains it, so in this case, the `open()` method would be interpreted as the `Window.open()` method, not `Document.open()`.

Window and Frame Names |  | Window and Variable Lifetime