O'Reilly logo

JavaScript Pocket Reference, 3rd Edition by David Flanagan

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 4. Statements

Chapter 3 described expressions as JavaScript phrases. By that analogy, statements are JavaScript sentences or commands. Just as English sentences are terminated and separated from each other with periods, JavaScript statements are terminated with semicolons (Optional Semicolons). Expressions are evaluated to produce a value, but statements are executed to make something happen.

One way to “make something happen” is to evaluate an expression that has side effects. Expressions with side effects, such as assignments and function invocations, can stand alone as statements, and when used this way they are known as expression statements. A similar category of statements are the declaration statements that declare new variables and define new functions.

JavaScript programs are nothing more than a sequence of statements to execute. By default, the JavaScript interpreter executes these statements one after another in the order they are written. Another way to “make something happen” is to alter this default order of execution, and JavaScript has a number of statements or control structures that do just this:

  • Conditionals are statements like if and switch that make the JavaScript interpreter execute or skip other statements depending on the value of an expression.

  • Loops are statements like while and for that execute other statements repetitively.

  • Jumps are statements like break, return, and throw that cause the interpreter to jump to another part of the program.

Table 4-1 summarizes JavaScript statement syntax, and the sections that follow it describe each statement in more detail.

Table 4-1. JavaScript statement syntax

Statement SyntaxPurpose
break break [label];

Exit from the innermost loop or switch or from named enclosing statement

case case expression:

Label a statement within a switch

continue continue [label];

Begin next iteration of the innermost loop or the named loop

debugger debugger;

Debugger breakpoint

default default:

Label the default statement within a switch

do/while do statement while (expression);

An alternative to the while loop

empty ;

Do nothing

for for(init; test; incr) statement

An easy-to-use loop

for/in for (var in object) statement

Enumerate the properties of object

function function name([param[,...]]) { body }

Declare a function named name

if/else if (expr) statement1 [else statement2]

Execute statement1 or statement2

label label: statement

Give statement the name label

return return [expression];

Return a value from a function

switch switch (expression) { statements }

Multiway branch to case or default: labels

throw throw expression;

Throw an exception

try

try {statements}

[catch { statements }]

[finally { statements }]

Handle exceptions

use strict "use strict";

Apply strict mode restrictions to script or function

var var name [ = expr] [ ,... ];

Declare and initialize one or more variables

while while (expression) statement

A basic loop construct

with with (object) statement

Extend the scope chain (forbidden in strict mode)

Expression Statements

The simplest kinds of statements in JavaScript are expressions that have side effects. This sort of statement was shown in Chapter 3. Assignment statements are one major category of expression statements. For example:

greeting = "Hello " + name;
i *= 3;

The increment and decrement operators, ++ and --, are related to assignment statements. These have the side effect of changing a variable value, just as if an assignment had been performed:

counter++;

The delete operator has the important side effect of deleting an object property. Thus, it is almost always used as a statement, rather than as part of a larger expression:

delete o.x;

Function calls are another major category of expression statements. For example:

alert(greeting);
window.close();

These client-side function calls are expressions, but they have side effects that affect the web browser and are used here as statements.

Compound and Empty Statements

A statement block combines multiple statements into a single compound statement. A statement block is simply a sequence of statements enclosed within curly braces. Thus, the following lines act as a single statement and can be used anywhere that JavaScript expects a single statement:

{
    x = Math.PI;
    cx = Math.cos(x);
    console.log("cos(π) = " + cx);
}

Combining statements into larger statement blocks is extremely common in JavaScript programming. Just as expressions often contain subexpressions, many JavaScript statements contain substatements. Formally, JavaScript syntax usually allows a single substatement. For example, the while loop syntax includes a single statement that serves as the body of the loop. Using a statement block, you can place any number of statements within this single allowed substatement.

A compound statement allows you to use multiple statements where JavaScript syntax expects a single statement. The empty statement is the opposite: it allows you to include no statements where one is expected.

The empty statement looks like this:

;

The JavaScript interpreter takes no action when it executes an empty statement. The empty statement is occasionally useful when you want to create a loop that has an empty body:

// Initialize the elements of a to 0
for(i = 0; i < a.length; a[i++] = 0) /* empty */;

Declaration Statements

The var and function are declaration statements—they declare or define variables and functions. These statements define identifiers (variable and function names) that can be used elsewhere in your program and assign values to those identifiers. Declaration statements don’t do much themselves, but by creating variables and functions they, in an important sense, define the meaning of the other statements in your program.

var

The var statement declares a variable or variables. Here’s the syntax:

var name_1 [ = value_1] [ ,..., name_n [= value_n]]

The var keyword is followed by a comma-separated list of variables to declare; each variable in the list may optionally have an initializer expression that specifies its initial value. For example:

var i;                          // One simple variable
var j = 0;                      // One var, one value
var p, q;                       // Two variables
var greeting = "hello" + name;  // A complex initializer
var x = 2, y = x*x;             // Second var uses first
var x = 2,                      // Multiple variables...
    f = function(x) { return x*x }, // each on its 
    y = f(x);                       // own line

If a var statement appears within the body of a function, it defines local variables, scoped to that function. When var is used in top-level code, it declares global variables, visible throughout the JavaScript program.

If no initializer is specified for a variable with the var statement, the variable’s initial value is undefined.

Note that the var statement can also appear as part of the for and for/in loops:

for(var i = 0; i < 10; i++) console.log(i);
for(var i = 0, j=10; i < 10; i++,j--) console.log(i*j);
for(var i in o) console.log(i);

function

The function keyword is used to define functions. We saw it in function definition expressions in Function Definition. It can also be used in statement form. Consider the following two functions:

// Expression assigned to a variable
var f = function(x) { return x+1; }
// The statement form includes the variable name
function f(x) { return x+1; }

A function declaration statement has the following syntax:

function funcname([arg1 [, arg2 [..., argn]]]) {
      statements
}

funcname is an identifier that names the function being declared. The function name is followed by a comma-separated list of parameter names in parentheses. These identifiers can be used within the body of the function to refer to the argument values passed when the function is invoked.

The body of the function is composed of any number of JavaScript statements, contained within curly braces. These statements are not executed when the function is defined. Instead, they are associated with the new function object for execution when the function is invoked.

Here are some more examples of function declarations:

function hypotenuse(x, y) {
    return Math.sqrt(x*x + y*y);
}

function factorial(n) {       // A recursive function
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

Function declaration statements may appear in top-level JavaScript code, or they may be nested within other functions. When nested, however, function declarations may only appear at the top level of the function they are nested within. That is, function definitions may not appear within if statements, while loops, or any other statements.

Function declaration statements differ from function definition expressions in that they include a function name. Both forms create a new function object, but the function declaration statement also declares the function name as a variable and assigns the function object to it. Like variables declared with var, functions defined with function definition statements are implicitly “hoisted” to the top of the containing script or function, so that all functions in a script or all nested functions in a function are declared before any other code is run. This means that you can invoke a JavaScript function before you declare it.

Conditionals

Conditional statements execute or skip other statements depending on the value of a specified expression. These statements are the decision points of your code, and they are also sometimes known as “branches.” If you imagine a JavaScript interpreter following a path through your code, the conditional statements are the places where the code branches into two or more paths and the interpreter must choose which path to follow.

if

The if statement is the fundamental control statement that allows JavaScript to execute statements conditionally. This statement has two forms. The first is:

if (expression)
    statement

In this form, expression is evaluated. If the resulting value is truthy, statement is executed. If expression is falsy, statement is not executed:

if (username == null) // If username is null or undefined,
    username = "John Doe";  // define it

Note that the parentheses around the expression are a required part of the syntax for the if statement.

The second form of the if statement introduces an else clause that is executed when expression is false. Its syntax is:

if (expression)
      statement1
else
      statement2

This form of the statement executes statement1 if expression is truthy and executes statement2 if expression is falsy. For example:

if (n == 1) {
    console.log("You have 1 new message.");
}
else {
    console.log("You have " + n + " new messages.");
}

else if

The if/else statement evaluates an expression and executes one of two pieces of code, depending on the outcome. But what about when you need to execute one of many pieces of code? One way to do this is with an else if statement. else if is not really a JavaScript statement, but simply a frequently used programming idiom that results when repeated if/else statements are used:

if (n == 1) {
    // Execute code block #1
}
else if (n == 2) {
    // Execute code block #2
}
else if (n == 3) {
    // Execute code block #3
}
else {
    // If all else fails, execute block #4
}

There is nothing special about this code. It is just a series of if statements, where each following if is part of the else clause of the previous statement. Using the else if idiom is preferable to, and more legible than, writing these statements out in their syntactically equivalent, fully nested form:

if (n == 1) {
    // Execute code block #1
}
else {
    if (n == 2) {
        // Execute code block #2
    }
    else {
        if (n == 3) {
            // Execute code block #3
        }
        else {
            // If all else fails, execute block #4
        }
    }
}

switch

An if statement causes a branch in the flow of a program’s execution, and you can use the else if idiom to perform a multiway branch. This is not the best solution, however, when all of the branches depend on the value of the same expression. In this case, it is wasteful to repeatedly evaluate that expression in multiple if statements.

The switch statement handles exactly this situation. The switch keyword is followed by an expression in parentheses and a block of code in curly braces:

switch(expression) {
      statements
}

However, the full syntax of a switch statement is more complex than this. Various locations in the block of code are labeled with the case keyword followed by an expression and a colon. case is like a labeled statement, except that instead of giving the labeled statement a name, it associates an expression with the statement. When a switch executes, it computes the value of expression and then looks for a case label whose expression evaluates to the same value (where sameness is determined by the === operator). If it finds one, it starts executing the block of code at the statement labeled by the case. If it does not find a case with a matching value, it looks for a statement labeled default:. If there is no default: label, the switch statement skips the block of code altogether.

The following switch statement is equivalent to the repeated if/else statements shown in the previous section:

switch(n) {
  case 1:                     // Start here if n === 1
    // Execute code block #1.
    break;                    // Stop here
  case 2:                     // Start here if n === 2
    // Execute code block #2.
    break;                    // Stop here
  case 3:                     // Start here if n === 3
    // Execute code block #3.
    break;                    // Stop here
  default:                    // If all else fails...
    // Execute code block #4.
    break;                    // stop here
}

Note the break keyword used at the end of each case in the code above. The break statement, described later in this chapter, causes the interpreter to break out of the switch statement and continue with the statement that follows it. The case clauses in a switch statement specify only the starting point of the desired code; they do not specify any ending point. In the absence of break statements, a switch statement begins executing its block of code at the case label that matches the value of its expression and continues executing statements until it reaches the end of the block. Usually you will want to end every case with a break or return statement.

Here is a more realistic example of the switch statement; it converts a value to a string in a way that depends on the type of the value:

function convert(x) {
    switch(typeof x) {
      case 'number': // Convert to a hexadecimal integer
        return x.toString(16);
      case 'string': // Enclose it in quotes
        return '"' + x + '"';
      default:       // Any other type
        return String(x);
    }
}

Note that in the two previous examples, the case keywords are followed by number and string literals, respectively. This is how the switch statement is most often used in practice, but note that the ECMAScript standard allows each case to be followed by an arbitrary expression.

Loops

To understand conditional statements, we imagined the JavaScript interpreter following a branching path through your source code. The looping statements are those that bend that path back upon itself to repeat portions of your code. JavaScript has four looping statements: while, do/while, for, and for/in.

while

The while statement is JavaScript’s basic loop. It has the following syntax:

while (expression)
      statement

To execute a while statement, the interpreter first evaluates expression. If the value of the expression is falsy, then the interpreter skips over the statement that serves as the loop body and moves on to the next statement in the program. If, on the other hand, the expression is truthy, the interpreter executes the statement and repeats, jumping back to the top of the loop and evaluating expression again. Another way to say this is that the interpreter executes statement repeatedly while the expression is truthy. Note that you can create an infinite loop with the syntax while(true).

Here is an example of a while loop that prints the numbers from 0 to 9:

var count = 0;
while (count < 10) {
    console.log(count);
    count++;
}

As you can see, the variable count starts off at 0 and is incremented each time the body of the loop runs. Once the loop has executed 10 times, the expression becomes false (i.e., the variable count is no longer less than 10), the while statement finishes, and the interpreter can move on to the next statement in the program.

do/while

The do/while loop is like a while loop, except that the loop expression is tested at the bottom of the loop rather than at the top. This means that the body of the loop is always executed at least once. The syntax of this relatively uncommon loop is:

do
      statement
  while (expression);

Here’s an example of a do/while loop:

function printArray(a) {
    var len = a.length, i = 0;
    if (len == 0)
        console.log("Empty Array");
    else {
        do {
            console.log(a[i]);
        } while (++i < len);
    }
}

for

The for statement simplifies loops that follow a common pattern. Most loops have a counter variable of some kind. This variable is initialized before the loop starts and is tested before each iteration of the loop. Finally, the counter variable is incremented or otherwise updated at the end of the loop body, just before the variable is tested again. In this kind of loop, the initialization, the test, and the update are the three crucial manipulations of a loop variable. The for statement encodes each of these three manipulations as an expression and makes those expressions an explicit part of the loop syntax:

for(initialize ; test ; increment)
      statement

initialize, test, and increment are three expressions (separated by semicolons) that are responsible for initializing, testing, and incrementing the loop variable. Putting them all in the first line of the loop makes it easy to understand what a for loop is doing and prevents mistakes such as forgetting to initialize or increment the loop variable.

The simplest way to explain how a for loop works is to show the equivalent while loop:

initialize;
  while(test) {
      statement
      increment;
  }

In other words, the initialize expression is evaluated once, before the loop begins. To be useful, this expression must have side effects (usually an assignment). JavaScript also allows initialize to be a var variable declaration statement so that you can declare and initialize a loop counter at the same time. The test expression is evaluated before each iteration and controls whether the body of the loop is executed. If test evaluates to a truthy value, the statement that is the body of the loop is executed. Finally, the increment expression is evaluated. Again, this must be an expression with side effects in order to be useful. Generally, either it is an assignment expression, or it uses the ++ or -- operators.

We can print the numbers from 0 to 9 with a for loop like the following. Contrast it with the equivalent while loop shown above:

for(var count = 0; count < 10; count++)
    console.log(count);

for/in

The for/in statement uses the for keyword, but it is a completely different kind of loop than the regular for loop. A for/in loop looks like this:

for (variable in object)
      statement

variable typically names a variable, but it may also be a var statement that declares a single variable. object is an expression that evaluates to an object. As usual, statement is the statement or statement block that serves as the body of the loop.

It is easy to use a regular for loop to iterate through the elements of an array:

// Assign array indexes to variable i
for(var i = 0; i < a.length; i++) 
    console.log(a[i]); // Print each array element

The for/in loop makes it easy to do the same for the properties of an object:

// Assign property names of o to variable p
for(var p in o)
    console.log(o[p]); // Print each property

To execute a for/in statement, the JavaScript interpreter first evaluates the object expression and then executes the body of the loop once for each enumerable property of the resulting object. Before each iteration, however, the interpreter assigns the name of the property to the variable.

The for/in loop does not actually enumerate all properties of an object, only the enumerable properties (see Property Attributes). The various built-in methods defined by core JavaScript are not enumerable. All objects have a toString() method, for example, but the for/in loop does not enumerate this toString property. In addition to built-in methods, many other properties of the built-in objects are nonenumerable. All properties and methods defined by your code are enumerable, however. (But in ECMAScript 5, you can make them nonenumerable using techniques explained in Property Attributes.)

The ECMAScript specification does not describe the order in which the for/in loop enumerates the properties of an object. In practice, however, JavaScript implementations from all major browser vendors enumerate the properties of simple objects in the order in which they were defined, with older properties enumerated first. If an object was created as an object literal, its enumeration order is the same order that the properties appear in the literal. Note that this enumeration order does not apply to all objects. In particular, if an object includes array index properties, those properties may be enumerated in numeric order rather than in creation order.

Jumps

Another category of JavaScript statements are jump statements. As the name implies, these cause the JavaScript interpreter to jump to a new location in the source code. The break statement makes the interpreter jump to the end of a loop or other statement. continue makes the interpreter skip the rest of the body of a loop and jump back to the top of a loop to begin a new iteration. JavaScript allows statements to be named, or labeled, and the break and continue can identify the target loop or other statement label. The return statement makes the interpreter jump from a function invocation back to the code that invoked it and also supplies the value for the invocation. The throw statement raises, or “throws,” an exception and is designed to work with the try/catch/finally statement, which establishes a block of exception handling code.

Labeled Statements

Any statement may be labeled by preceding it with an identifier and a colon:

identifier: statement

By labeling a statement, you give it a name that you can use to refer to it elsewhere in your program. You can label any statement, although it is only useful to label statements that have bodies, such as loops and conditionals. By giving a loop a name, you can use break and continue statements inside the body of the loop to exit the loop or to jump directly to the top of the loop to begin the next iteration. break and continue are the only JavaScript statements that use statement labels; they are covered later in this chapter. Here is an example of a labeled while loop and a continue statement that uses the label.

mainloop: while(token != null) {
    // Code omitted...
    continue mainloop; // Jump to top of the named loop
    // More code omitted...
}

break

The break statement, used alone, causes the innermost enclosing loop or switch statement to exit immediately. Its syntax is simple:

break;

Because it causes a loop or switch to exit, this form of the break statement is legal only if it appears inside one of these statements.

You’ve already seen examples of the break statement within a switch statement. In loops, it is typically used to exit prematurely when, for whatever reason, there is no longer any need to complete the loop. When a loop has complex termination conditions, it is often easier to implement some of these conditions with break statements rather than trying to express them all in a single loop expression. The following code searches the elements of an array for a particular value. The loop terminates in the normal way when it reaches the end of the array; it terminates with a break statement if it finds what it is looking for in the array:

for(var i = 0; i < a.length; i++) {
    if (a[i] == target) break;
}

Although it is rarely used in practice, JavaScript allows the break keyword to be followed by a statement label (just the identifier, with no colon):

break labelname;

When break is used with a label, it jumps to the end of, or terminates, the enclosing statement that has the specified label. It is a syntax error to use break in this form if there is no enclosing statement with the specified label. With this form of the break statement, the named statement need not be a loop or switch: break can “break out of” any enclosing statement.

continue

The continue statement is similar to the break statement. Instead of exiting a loop, however, continue restarts a loop at the next iteration. The continue statement’s syntax is just as simple as the break statement’s:

continue;

The continue statement can also be used with a label:

continue labelname;

The continue statement, in both its labeled and unlabeled forms, can be used only within the body of a loop. Using it anywhere else causes a syntax error.

The following example shows an unlabeled continue statement being used to skip the rest of the current iteration of a loop when an error occurs:

for(i = 0; i < data.length; i++) {
    if (isNaN(data[i])) continue; // Skip non-numbers.
    total += data[i];
}

Like the break statement, the continue statement can be used in its labeled form within nested loops, when the loop to be restarted is not the immediately enclosing loop.

return

Recall that function invocations are expressions and that all expressions have values. A return statement within a function specifies the value of invocations of that function. Here’s the syntax of the return statement:

return expression;

A return statement may appear only within the body of a function. It is a syntax error for it to appear anywhere else. When the return statement is executed, the function that contains it returns the value of expression to its caller. For example:

function square(x) { return x*x; } // Returns x squared
square(2) // This invocation evaluates to 4

With no return statement, a function invocation simply executes each of the statements in the function body in turn until it reaches the end of the function, and then returns to its caller. In this case, the invocation expression evaluates to undefined. The return statement can also be used without an expression to make the function return undefined before it reaches the end of its body. For example:

function display_object(o) {
    // Return immediately if o is null or undefined.
    if (!o) return;
    // Rest of function goes here...
}

throw

An exception is a signal that indicates that some sort of exceptional condition or error has occurred. To throw an exception is to signal such an error or exceptional condition. To catch an exception is to handle it—to take whatever actions are necessary or appropriate to recover from the exception. In JavaScript, exceptions are thrown whenever a runtime error occurs and whenever the program explicitly throws one using the throw statement. Exceptions are caught with the try/catch/finally statement, which is described next.

The throw statement has the following syntax:

throw expression;

expression may evaluate to a value of any type. You might throw a number that represents an error code or a string that contains a human-readable error message. The Error class and its subclasses are used when the JavaScript interpreter itself throws an error, and you can use them as well. An Error object has a name property that specifies the type of error and a message property that holds the string passed to the constructor function (see the Error class in the reference section). Here is an example function that throws an Error object when invoked with an invalid argument:

function factorial(x) {
    // If x is invalid, throw an exception!
    if (x < 0) throw new Error("x must not be negative");
    // Otherwise, compute a value and return normally
    for(var f = 1; x > 1; f *= x, x--) /* empty */ ;
    return f;
}

When an exception is thrown, the JavaScript interpreter immediately stops normal program execution and jumps to the nearest exception handler. Exception handlers are written using the catch clause of the try/catch/finally statement, which is described in the next section. If the block of code in which the exception was thrown does not have an associated catch clause, the interpreter checks the next highest enclosing block of code to see if it has an exception handler associated with it. This continues until a handler is found. If an exception is thrown in a function that does not contain a try/catch/finally statement to handle it, the exception propagates up to the code that invoked the function. In this way, exceptions propagate up through the lexical structure of JavaScript methods and up the call stack. If no exception handler is ever found, the exception is treated as an error and is reported to the user.

try/catch/finally

The try/catch/finally statement is JavaScript’s exception handling mechanism. The try clause of this statement simply defines the block of code whose exceptions are to be handled. The try block is followed by a catch clause, which is a block of statements that are invoked when an exception occurs anywhere within the try block. The catch clause is followed by a finally block containing cleanup code that is guaranteed to be executed, regardless of what happens in the try block. Both the catch and finally blocks are optional, but a try block must be accompanied by at least one of these blocks. The try, catch, and finally blocks all begin and end with curly braces. These braces are a required part of the syntax and cannot be omitted, even if a clause contains only a single statement.

The following code illustrates the syntax and purpose of the try/catch/finally statement:

try {
  // Normally, this code runs from the top of the block
  // to the bottom without problems. But it can
  // sometimes throw an exception, either directly, with
  // a throw statement, or indirectly, by calling a
  // method that throws an exception.
}
catch (e) {
  // The statements in this block are executed if, and
  // only if, the try block throws an exception. These
  // statements can use the local variable e to refer
  // to the Error object or other value that was thrown.
  // This block may handle the exception somehow, may
  // ignore the exception by doing nothing, or may
  // rethrow the exception with throw.
}
finally {
  // This block contains statements that are always
  // executed, regardless of what happens in the try
  // block. They are executed when the try block
  // terminates:
  //   1) normally, after reaching the bottom
  //   2) because of a break, continue, or return
  //   3) with an exception handled by a catch above
  //   4) with an uncaught exception that is propagating
}

Note that the catch keyword is followed by an identifier in parentheses. This identifier is like a function parameter. When an exception is caught, the value associated with the exception (an Error object, for example) is assigned to this parameter. Unlike regular variables, the identifier associated with a catch clause has block scope—it is only defined within the catch block.

Here is a realistic example of the try/catch statement. It uses the factorial() method defined in the previous section and the client-side JavaScript methods prompt() and alert() for input and output:

try {
    // Ask the user to enter a number
    var n = Number(prompt("Enter an number", ""));
    // Compute the factorial of the number,
    // assuming the input is valid.
    var f = factorial(n);
    // Display the result
    alert(n + "! = " + f);  
}
catch (ex) {    // We end up here on invalid input.
    alert(ex);  // Tell the user what the error is.
}

Miscellaneous Statements

This section describes the remaining three JavaScript statements—with, debugger, and use strict.

with

When JavaScript looks up the value of a variable, it first looks at the variables defined within the current function, then (if the function is nested) at variables defined in enclosing functions and finally at global variables. The with statement temporarily alters the way variables are looked up by specifying an object whose properties should be treated as if they were variables. It has the following syntax:

with (object)
    statement

This statement executes statement somewhat as if it was the body of a nested function and the properties of object were parameters passed to that function.

The with statement is forbidden in strict mode (see “use strict”) and should be considered deprecated in nonstrict mode: avoid using it whenever possible. JavaScript code that uses with is difficult to optimize and is likely to run much more slowly than the equivalent code written without the with statement.

debugger

The debugger statement normally does nothing. If, however, a debugger program is available and is running, then an implementation may (but is not required to) perform some kind of debugging action. In practice, this statement acts like a breakpoint: execution of JavaScript code stops and you can use the debugger to print variables’ values, examine the call stack, and so on. Suppose, for example, that you are getting an exception in your function f() because it is being called with an undefined argument, and you can’t figure out where this call is coming from. To help you in debugging this problem, you might alter f() so that it begins like this:

function f(o) {
  if (o === undefined) debugger; // Debug hook
  // The rest of the function goes here.
}

Now, when f() is called with no argument, execution will stop, and you can use the debugger to inspect the call stack and find out where this incorrect call is coming from.

The debugger statement was formally added to the language by ECMAScript 5, but it has been implemented by major browser vendors for quite some time.

“use strict”

"use strict" is a directive introduced in ECMAScript 5. Directives are not statements (but are close enough that "use strict" is documented here). "use strict" does not involve any JavaScript keywords: it is simply a JavaScript string literal expression, and is ignored by ECMAScript 3 interpreters. When placed at the beginning of a script or of a function body, however, it has special meaning to an ECMAScript 5 interpreter.

The purpose of a "use strict" directive is to indicate that the code that follows (in the script or function) is strict code. Strict code is executed in strict mode. The strict mode of ECMAScript 5 is a restricted subset of the language that fixes a few important language deficiencies and provides stronger error checking and increased security. The most important differences between strict mode and non-strict mode are the following:

  • The with statement is not allowed in strict mode.

  • In strict mode, all variables must be declared: a ReferenceError is thrown if you assign a value to an identifier that is not a declared variable, parameter, or property of the global object. (In nonstrict mode, this implicitly declares a global variable by adding a new property to the global object.)

  • In strict mode, functions invoked as functions (rather than as methods) have a this value of undefined. (In nonstrict mode, functions invoked as functions are always passed the global object as their this value.) This difference can be used to determine whether an implementation supports strict mode:

    var hasStrictMode = (function() {
        "use strict";
         return this === undefined;
    }());
  • In strict mode, assignments to nonwritable properties and attempts to create new properties on nonextensible objects throw a TypeError. (In nonstrict mode, these attempts fail silently.) Similarly, in strict mode, an attempt to delete a nonconfigurable property or a nonproperty value throws a TypeError or SyntaxError. (In nonstrict mode, the attempt fails and the delete expression evaluates to false.)

  • In strict mode, code passed to eval() cannot declare variables or define functions in the caller’s scope as it can in nonstrict mode. Instead, variable and function definitions live in a new scope created for the eval(). This scope is discarded when the eval() returns.

  • In strict mode, octal integer literals (beginning with a 0 that is not followed by an x) are not allowed. (In nonstrict mode, some implementations allow octal literals.)

  • In strict mode, the identifiers eval and arguments are treated like keywords, and you are not allowed to change their value.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required