0% found this document useful (0 votes)
11K views

Variables - JavaScript - The Definitive Guide, 5th Edition (Book)

1. The document discusses variables in JavaScript, explaining that a variable stores a value and allows programmers to manipulate data. 2. Variables in JavaScript are untyped, meaning a variable can hold values of any data type, unlike strongly typed languages like Java. 3. Variables must be declared with the var keyword before they are used, and variables can be declared without being initialized or assigned a value.

Uploaded by

linfengmian2024
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11K views

Variables - JavaScript - The Definitive Guide, 5th Edition (Book)

1. The document discusses variables in JavaScript, explaining that a variable stores a value and allows programmers to manipulate data. 2. Variables in JavaScript are untyped, meaning a variable can hold values of any data type, unlike strongly typed languages like Java. 3. Variables must be declared with the var keyword before they are used, and variables can be declared without being initialized or assigned a value.

Uploaded by

linfengmian2024
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

SIGN IN TRY NOW

See everything available through the O’Reilly learning platform Search

JavaScript: The Definitive Guide, 5th Edition by David Flanagan

Chapter 4. Variables


A variable is a name associated with a value; we say that the variable stores
or contains the value. Variables allow you to store and manipulate data in
your programs. For example, the following line of JavaScript assigns the
value 2 to a variable named i:

i = 2;

And the following line adds 3 to i and assigns the result to a new variable,
sum:

var sum = i + 3;

These two lines of code demonstrate just about everything you need to
know about variables. However, to fully understand how variables work in
JavaScript, you need to master a few more concepts. Unfortunately, these
concepts require more than a couple of lines of code to explain! The rest of
this chapter explains the typing, declaration, scope, contents, and resolution
SIGN IN TRY NOW
of variables. It also explores garbage collection and the variable/property
duality.[*]

Variable Typing
An important difference between JavaScript and languages such as Java and
C is that JavaScript is untyped. This means, in part, that a JavaScript variable
can hold a value of any datatype, unlike a Java or C variable, which can hold
only the one particular type of data for which it is declared. For example, it is
perfectly legal in JavaScript to assign a number to a variable and then later
assign a string to that variable:

i = 10;
i = "ten";

In C, C++, Java, or any other strongly typed language, code like this is illegal.

A feature related to JavaScript’s lack of typing is that the language con-


veniently and automatically converts values from one type to another, as
necessary. If you attempt to append a number to a string, for example,
JavaScript automatically converts the number to the corresponding string so
that it can be appended. Datatype conversion is covered in detail in
Chapter 3.

JavaScript is obviously a simpler language for being untyped. The advantage


of strongly typed languages such as C++ and Java is that they enforce rigor-
ous programming practices, which makes it easier to write, maintain, and re-
use long, complex programs. Since many JavaScript programs are shorter
scripts, this rigor is not necessary, and we benefit from the simpler syntax.
Variable Declaration
SIGN IN TRY NOW

Before you use a variable in a JavaScript program, you must declare it.[*]
Variables are declared with the var keyword, like this:

var i;
var sum;

You can also declare multiple variables with the same var keyword:

var i, sum;

And you can combine variable declaration with variable initialization:

var message = "hello";


var i = 0, j = 0, k = 0;

If you don’t specify an initial value for a variable with the var statement,
the variable is declared, but its initial value is undefined until your code
stores a value into it.

Note that the var statement can also appear as part of the for and for/in
loops (introduced in Chapter 6), allowing you to succinctly declare the loop
variable as part of the loop syntax itself. For example:

for(var i = 0; i < 10; i++) document.write(i, ">br<");


for(var i = 0, j=10; i < 10; i++,j--) document.write(i*j, ">br<");
for(var i in o) document.write(i, ">br<");

Variables declared with var are permanent: attempting to delete them with
the delete operator causes an error. (The delete operator is introduced in
Chapter 5.)
SIGN IN TRY NOW

Repeated and Omitted Declarations

It is legal and harmless to declare a variable more than once with the var
statement. If the repeated declaration has an initializer, it acts as if it were
simply an assignment statement.

If you attempt to read the value of an undeclared variable, JavaScript gener-


ates an error. If you assign a value to a variable that you have not declared
with var, JavaScript implicitly declares that variable for you. Note, however,
that implicitly declared variables are always created as global variables, even
if they are used within the body of a function. To prevent the creation of a
global variable (or the use of an existing global variable) when you meant to
create a local variable to use within a single function, you must always use
the var statement within function bodies. It’s best to use var for all vari-
ables, whether global or local. (The distinction between local and global
variables is explored in more detail in the next section.)

Variable Scope
The scope of a variable is the region of your program in which it is defined. A
global variable has global scope; it is defined everywhere in your JavaScript
code. On the other hand, variables declared within a function are defined
only within the body of the function. They are local variables and have local
scope. Function parameters also count as local variables and are defined
only within the body of the function.

Within the body of a function, a local variable takes precedence over a


global variable with the same name. If you declare a local variable or func-
tion parameter with the same name as a global variable, you effectively hide
the global variable. For example, the following code prints the word
SIGN IN TRY NOW
“local”:

var scope = "global"; // Declare a global variable


function checkscope( ) {
var scope = "local"; // Declare a local variable with the sa
document.write(scope); // Use the local variable, not the glob
}
checkscope( ); // Prints "local"

Although you can get away with not using the var statement when you
write code in the global scope, you must always use var to declare local
variables. Consider what happens if you don’t:

scope = "global"; // Declare a global variable, even with


function checkscope( ) {
scope = "local"; // Oops! We just changed the global var
document.write(scope); // Uses the global variable
myscope = "local"; // This implicitly declares a new globa
document.write(myscope); // Uses the new global variable
}
checkscope( ); // Prints "locallocal"
document.write(scope); // This prints "local"
document.write(myscope); // This prints "local"

In general, functions do not know what variables are defined in the global
scope or what they are being used for. Thus, if a function uses a global vari-
able instead of a local one, it runs the risk of changing a value on which
some other part of the program relies. Fortunately, avoiding this problem is
simple: declare all variables with var.

Function definitions can be nested. Each function has its own local scope, so
it is possible to have several nested layers of local scope. For example:
var scope = "global scope"; // A global variable
SIGN IN TRY NOW
function checkscope( ) {
var scope = "local scope"; // A local variable
function nested( ) {
var scope = "nested scope"; // A nested scope of local varia
document.write(scope); // Prints "nested scope"
}
nested( );
}
checkscope( );

No Block Scope

Note that unlike C, C++, and Java, JavaScript does not have block-level
scope. All variables declared in a function, no matter where they are de-
clared, are defined throughout the function. In the following code, the vari-
ables i, j, and k all have the same scope: all three are defined throughout
the body of the function. This would not be the case if the code were written
in C, C++, or Java:

function test(o) {
var i = 0; // i is defined throughout functi
if (typeof o == "object") {
var j = 0; // j is defined everywhere, not j
for(var k=0; k < 10; k++) { // k is defined everywhere, not j
document.write(k);
}
document.write(k); // k is still defined: prints 10
}
document.write(j); // j is defined, but may not be i
}

The rule that all variables declared in a function are defined throughout the
function can cause surprising results. The following code illustrates this:
var scope = "global";
SIGN IN TRY NOW
function f( ) {
alert(scope); // Displays "undefined", not "global"
var scope = "local"; // Variable initialized here, but defined e
alert(scope); // Displays "local"
}
f( );

You might think that the first call to alert( ) would display “global”,
because the var statement declaring the local variable has not yet been ex-
ecuted. Because of the scope rules, however, this is not what happens. The
local variable is defined throughout the body of the function, which means
the global variable by the same name is hidden throughout the function.
Although the local variable is defined throughout, it is not actually initialized
until the var statement is executed. Thus, the function f in the previous ex-
ample is equivalent to the following:

function f( ) {
var scope; // Local variable is declared at the start of th
alert(scope); // It exists here, but still has "undefined" val
scope = "local"; // Now we initialize it and give it a value
alert(scope); // And here it has a value
}

This example illustrates why it is good programming practice to place all


your variable declarations together at the start of any function.

Undefined Versus Unassigned

The examples in the previous section demonstrate a subtle point in


JavaScript programming: there are two different kinds of undefined vari-
ables. The first kind of undefined variable is one that has never been de-
clared. An attempt to read the value of such an undeclared variable causes a
runtime error. Undeclared variables are undefined because they simply do
not exist. As described earlier, assigning a value to anSIGN IN TRY NOW
undeclared variable
does not cause an error; instead, it implicitly declares the variable in the
global scope.

The second kind of undefined variable is one that has been declared but has
never had a value assigned to it. If you read the value of one of these vari-
ables, you obtain its default value, undefined. This type of undefined vari-
able might more usefully be called unassigned, to distinguish it from the
more serious kind of undefined variable that has not even been declared and
does not exist.

The following code fragment illustrates some of the differences between


truly undefined and merely unassigned variables:

var x; // Declare an unassigned variable. Its value is undefined.


alert(u); // Using an undeclared variable causes an error.
u = 3; // Assigning a value to an undeclared variable creates the

Primitive Types and Reference Types


The next topic we need to consider is the content of variables. We often say
that variables have or contain values. But just what is it that they contain?
To answer this seemingly simple question, we must look again at the
datatypes supported by JavaScript. The types can be divided into two
groups: primitive types and reference types. Numbers, boolean values, and
the null and undefined types are primitive. Objects, arrays, and functions
are reference types.

A primitive type has a fixed size in memory. For example, a number occupies
eight bytes of memory, and a boolean value can be represented with only
one bit. The number type is the largest of the primitive types. If each
JavaScript variable reserves eight bytes of memory, the variable can directly
SIGN IN TRY NOW
hold any primitive value.[*]

Reference types are another matter, however. Objects, for example, can be
of any length: they do not have a fixed size. The same is true of arrays: an ar-
ray can have any number of elements. Similarly, a function can contain any
amount of JavaScript code. Since these types do not have a fixed size, their
values cannot be stored directly in the eight bytes of memory associated
with each variable. Instead, the variable stores a reference to the value.
Typically, this reference is some form of pointer or memory address. It is not
the data value itself, but it tells the variable where to look to find the value.

The distinction between primitive and reference types is an important one


because they behave differently. Consider the following code that uses
numbers (a primitive type):

var a = 3.14; // Declare and initialize a variable


var b = a; // Copy the variable's value to a new variable
a = 4; // Modify the value of the original variable
alert(b) // Displays 3.14; the copy has not changed

There is nothing surprising about this code. Now consider what happens if
we change the code slightly so that it uses arrays (a reference type) instead
of numbers:

var a = [1,2,3]; // Initialize a variable to refer to an array


var b = a; // Copy that reference into a new variable
a[0] = 99; // Modify the array using the original reference
alert(b); // Display the changed array [99,2,3] using the new

If this result does not seem surprising to you, you’re already well familiar
with the distinction between primitive and reference types. If it does seem
surprising, take a closer look at the second line. Note that it is the reference
to the array value, not the array itself, that is being assigned in this state-
SIGN IN TRY NOW
ment. After that second line of code, we still have only one array object;
there just happens to be two references to it.

If the primitive-versus-reference type distinction is new to you, just try to


keep the variable contents in mind. Variables hold the actual values of primi-
tive types, but they hold only references to the values of reference types.
The differing behavior of primitive and reference types is explored in more
detail in By Value Versus by Reference.

You may have noticed that I did not specify whether strings are primitive or
reference types in JavaScript. Strings are an unusual case. They have variable
sizes, so obviously they cannot be stored directly in fixed-size variables. For
efficiency, you would expect JavaScript to copy references to strings, not
the actual contents of strings. On the other hand, strings behave like a prim-
itive type in many ways. The question of whether strings are a primitive or
reference type is actually moot because strings are immutable: there is no
way to change the contents of a string value. This means that you cannot
construct an example like the previous one that demonstrates that arrays are
copied by reference. In the end, it doesn’t matter much whether you think
of strings as an immutable reference type that behaves like a primitive type
or as a primitive type implemented with the internal efficiency of a reference
type.

Garbage Collection
Reference types do not have a fixed size; indeed, some of them can become
quite large. As we’ve already discussed, variables do not directly hold ref-
erence values. The value is stored at some other location, and the variables
merely hold a reference to that location. Now let’s focus briefly on the ac-
tual storage of the value.
Since strings, objects, and arrays do not have a fixed size, storage for them
SIGN IN TRY NOW
must be allocated dynamically, when the size is known. Every time a
JavaScript program creates a string, array, or object, the interpreter must al-
locate memory to store that entity. Whenever memory is dynamically allo-
cated like this, it must eventually be freed up for reuse, or the JavaScript in-
terpreter will use up all the available memory on the system and crash.

In languages such as C and C++, memory must be freed manually. It is the


programmer’s responsibility to keep track of all objects that are created
and to destroy them (freeing their memory) when they are no longer
needed. This can be an onerous task and is often the source of bugs.

Instead of requiring manual deallocation, JavaScript relies on a technique


called garbage collection. The JavaScript interpreter can detect when an ob-
ject will never again be used by the program. When it determines that an ob-
ject is unreachable (i.e., there is no longer any way to refer to it using the
variables in the program), it knows that the object is no longer needed and
its memory can be reclaimed. Consider the following lines of code, for
example:

var s = "hello"; // Allocate memory for a string


var u = s.toUpperCase( ); // Create a new string
s = u; // Overwrite reference to original string

After this code runs, the original string “hello” is no longer reachable;
there are no references to it in any variables in the program. The system de-
tects this fact and frees up its storage space for reuse.

Garbage collection is automatic and is invisible to the programmer. You need


to know only enough about garbage collection to trust that it works: to
know you can create all the garbage objects you want, and the system will
clean up after you!
Variables as Properties
SIGN IN TRY NOW

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 fun-
damentally the same as object properties.

The Global Object

When the JavaScript interpreter starts up, one of the first things it does, be-
fore executing any JavaScript code, is create a global object. The properties
of this object are the global variables of JavaScript programs. When you de-
clare 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, respec-
tively. You can read about these global values in Part III.

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 func-
tions, this has a different use, which is described in Chapter 8.

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 de-
fines the core global properties, such as parseInt and Math, and also
global client-side properties, such as navigator and screen.
Local Variables: The Call Object
SIGN IN TRY NOW

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 lifespan 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.

JavaScript Execution Contexts

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.) The obvi-
ous example is client-side JavaScript, in which each separate browser win-
dow, 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. 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 just yet how separate window and
SIGN IN TRY NOW
frame execution contexts are linked together in client-side JavaScript. That
topic is covered in detail in the discussion on the integration of JavaScript
with web browsers in Chapter 13. 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 func-
tions that are defined in another execution context, you’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 run-
ning a script from some random site out on the Internet. In general, you do
not want to allow the code in window B to be able to access the properties
of window A. If you do allow it to do so, window B 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 pre-
vents access from one execution context to another when such access
should not be permitted. We’ll return to this topic in JavaScript Security.

Variable Scope Revisited


When we first discussed the notion of variable scope, I based the definition
solely on the lexical structure of JavaScript code: global variables have
global scope, and variables declared in functions have local scope. If one
function definition is nested within another, variables declared within that
nested function have a nested local scope. Now that you know that global
variables are properties of a global object and that local variables are prop-
erties of a special call object, we can return to the notion of variable scope
and reconceptualize it. This new description of scope offers a useful way to
think about variables in many contexts; it provides a powerful new under-
SIGN IN TRY NOW
standing of how JavaScript works.

Every JavaScript execution context has a scope chain associated with it. This
scope chain is a list or chain of objects. When JavaScript code needs to look
up the value of a variable x (a process called variable name resolution), it
starts by looking at the first object in the chain. If that object has a property
named x, the value of that property is used. If the first object does not have
a property named x, JavaScript continues the search with the next object in
the chain. If the second object does not have a property named x, the search
moves on to the next object, and so on.

In top-level JavaScript code (i.e., code not contained within any function
definitions), the scope chain consists of a single object, the global object. All
variables are looked up in this object. If a variable does not exist, the vari-
able value is undefined. In a (nonnested) function, however, the scope chain
consists of two objects. The first is the function’s call object, and the sec-
ond is the global object. When the function refers to a variable, the call ob-
ject (the local scope) is checked first, and the global object (the global
scope) is checked second. A nested function would have three or more ob-
jects in its scope chain. Figure 4-1 illustrates the process of looking up a
variable name in the scope chain of a function.
SIGN IN TRY NOW

Figure 4-1. The scope chain and variable resolution

[*] Theseare tricky concepts, and a complete understanding of this chapter requires an understanding of concepts introduced in later chapters of the book. If you are
relatively new to programming, you may want to read only the first two sections of this chapter and then move on to Chapter 5, 6, and 7 before returning to finish
up the remainder of this chapter.

[*] If you don’t declare a variable explicitly, JavaScript will declare it implicitly for you.

[*] This is an oversimplification and is not intended as a description of an actual JavaScript implementation.

[*] 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, 5th Edition now with the
O’Reilly learning platform.

O’Reilly members experience books, live events, courses cu-


rated by job role, and more from O’Reilly and
nearly 200 top publishers.
START YOUR FREE TRIAL
SIGN IN TRY NOW

ABOUT O’REILLY
Teach/write/train
Careers

Press releases
Media coverage

Community partners
Affiliate program

Submit an RFP
Diversity

O’Reilly for marketers

SUPPORT

Contact us
Newsletters

Privacy policy

INTERNATIONAL

Australia & New Zealand


Hong Kong & Taiwan

India
Indonesia

Japan

DOWNLOAD THE O’REILLY APP

Take O’Reilly with you and learn anywhere, anytime on your phone and tablet.
WATCH ON YOUR BIG SCREEN

View all O’Reilly videos, Superstream events, and Meet the Expert sessions SIGN INhomeTRY
on your TV.NOW

DO NOT SELL MY PERSONAL INFORMATION

© 2023, O’Reilly Media, Inc. All trademarks and registered trademarks appearing on oreilly.com are the property of their
respective owners.
Terms of service • Privacy policy • Editorial independence

You might also like