You may have noticed by now that there are a
lot of similarities in JavaScript between variables and the
properties of objects. They are both assigned the same way, they are
used the same way in JavaScript expressions, and so on. Is there
really any fundamental difference between the variable
i
and the property i
of an
object o
? The answer is no. Variables in
JavaScript are fundamentally the same as object properties.
When the JavaScript interpreter starts up, one of the first things it does, before executing any JavaScript code, is create a global object. The properties of this object are the global variables of JavaScript programs. When you declare a global JavaScript variable, what you are actually doing is defining a property of the global object.
The JavaScript interpreter
initializes the global object with a number of properties that refer
to predefined values and functions. For example, the
Infinity
, parseInt
, and
Math
properties refer to the number infinity, the
predefined parseInt( )
function, and the
predefined Math object. You can read about these global values in the
core reference section of this book.
In top-level code (i.e., JavaScript code that is not part of a
function), you can use the JavaScript keyword this
to refer to the global object. Within functions,
this
has a different use, which is described in
Chapter 7.
In
client-side JavaScript, the Window object serves as the global object
for all JavaScript code contained in the browser window it
represents. This global Window object has a self-referential
window
property that can be used instead of
this
to refer to the global object. The Window
object defines the core global properties, such as
parseInt
and Math
, and also
global client-side properties, such as navigator
and screen
.
If global variables are properties of the special global object, then what are local variables? They too are properties of an object. This object is known as the call object. The call object has a shorter life span than the global object, but it serves the same purpose. While the body of a function is executing, the function arguments and local variables are stored as properties of this call object. The use of an entirely separate object for local variables is what allows JavaScript to keep local variables from overwriting the value of global variables with the same name.
Each time the JavaScript interpreter begins to execute a function, it creates a new execution context for that function. An execution context is, obviously, the context in which any piece of JavaScript code executes. An important part of the context is the object in which variables are defined. Thus, JavaScript code that is not part of any function runs in an execution context that uses the global object for variable definitions. And every JavaScript function runs in its own unique execution context with its own call object in which local variables are defined.
An interesting point to note is that JavaScript implementations may
allow multiple global execution contexts, each with a
different global object. (Although, in this
case, each global object is not entirely global.)[14] The obvious
example is client-side JavaScript, in which each separate browser
window, or each frame within a window, defines a separate global
execution context. Client-side JavaScript code in each frame or
window runs in its own execution context and has its own global
object. However, these separate client-side global objects have
properties that link them to one another. Thus, JavaScript code in
one frame might refer to another frame with the expression
parent.frames[1]
, and the global variable
x
in the first frame might be referenced by the
expression parent.frames[0].x
in the second frame.
You don’t need to fully understand how separate window and frame execution contexts are linked together in client-side JavaScript right now. We’ll cover that topic in detail when we discuss the integration of JavaScript with web browsers in Chapter 12. What you should understand now is that JavaScript is flexible enough that a single JavaScript interpreter can run scripts in different global execution contexts and that those contexts need not be entirely separate -- they can refer back and forth to each other.
This last point requires additional consideration. When JavaScript code in one execution context can read and write property values and execute functions that are defined in another execution context, we’ve reached a level of complexity that requires consideration of security issues. Take client-side JavaScript as an example. Suppose browser window A is running a script or contains information from your local intranet, and window B is running a script from some random site out on the Internet. In general, we do not want to allow the code in window B to be able to access the properties of window A. If we allow it to do this, it might be able to read sensitive company information and steal it, for example. Thus, in order to safely run JavaScript code, there must be a security mechanism that prevents access from one execution context to another when such access should not be permitted. We’ll return to this topic in Chapter 21.
[14] This is merely an aside; if it does not interest you, feel free to move on to the next section.
Get JavaScript: The Definitive Guide, Fourth Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.