Overview

This chapter gives a quick overview of the language. It is intentionally over-simplified and incomplete. The complete language is described in detail in the material that follows, but it is organized around the details. In order to make sense of the details, it is useful to see how the pieces fit together.

Whitespace

Whitespace can take the form of formatting characters or comments. Whitespace is usually insignificant, but it is occasionally necessary to use whitespace to separate sequences of characters that would otherwise be combined into a single token. For example, in the statement

var that = this;

the space between var and that cannot be removed, but the other spaces can be removed.

JavaScript offers two forms of comments, block comments formed with /* */, and line ending comments starting with //. Comments should be used liberally to improve the readability of your programs. Take care that the comments always accurately describe the code. Incorrect or obsolete comments are worse than no comments.

The /* */ form of block comments came from a language called PL/I. PL/I chose those strange pairs as the symbols for comments because they were unlikely to occur in that language's programs, except perhaps in string literals. In JavaScript, those pairs can also occur in regular expression literals, so block comments are not safe for commenting out blocks of code. For example,

/*
    var rm_a = /a*/.match(s);
*/

causes a syntax error. Iit is recommended that /* */ comments be avoided and // comments be used instead. In this book, // will be used exclusively.

Names

A name is a letter optionally followed by one or more letters, digits. The characters _ (underbar) and $ (dollar sign) are considered to be letters. A name that is a reserved word cannot be used as variable or parameter name:

abstract
boolean break byte
case catch char class const continue
debugger default delete do double
else enum export extends
false final finally float for function
goto
if implements import in instanceof int interface
long
native new null
package private protected public
return
short static super switch synchronized
this throw throws transient true try typeof
var volatile void
while with 

Most of the reserved words in this list are not used in the language. The list does not include some words like undefined, NaN, and Infinity that should have been reserved but were not.

ES3 adds two further restrictions on reserved words: A reserved word must be quoted when used as a key in an object literal. Reserved words may not be used with the . suffix operator select.

Names are used as statements, variables, parameters, property names, operators, and labels.

Objects

All values in the language except for null and undefined are objects. Objects are containers of properties that can have methods (functions) and that inherit properties from other objects. The object that is inherited from is said to be the prototype. Booleans, numbers, and strings are immutable objects.

Boolean

There are two boolean values, true and false.

Every value in the language is either truthy or falsy. The falsy values are

All other values are truthy, including true, the string 'false', and all objects.

Numbers

JavaScript has a single number type. Internally, it is represented as 64-bit floating point, the same as Java's double. Unlike most other programming languages, there is no separate integer type, so 1 and 1.0 are the same value.  This is a significant convenience because problems of overflow in short integers are completely avoided, and all you need to know about a number is that it is a number. A large class of numeric type errors is avoided. Integer wrap around errors are impossible, but underflow errors can occur.

If a number literal has an exponent part, then the value of the literal is computed by multiplying the part before the e by 10 raised to the power of the part after the e. So 100 and 1.0e2 are the same number.

Negative numbers can be formed by using the prefix operator.

The value NaN is a number value that is the result of an operation that cannot produce a normal result, such as division of zero by zero. NaN is not equal to any value, including itself. You can detect NaN with the isNaN global function.

The value Infinity represents all values greater than 1.79769313486231570e+308.

Numbers have methods. JavaScript also has a Math object that contains a set of functions that act on numbers.  For example, the Math.floor(number) method can be used to convert a number into an integer.

Strings

A string literal can be wrapped in single quotes or double quotes. It can contain zero or more characters. The \ (backslash) is the escape character. JavaScript was built at a time when Unicode was a 16-bit character set, so all characters in JavaScript are 16 bits wide.

JavaScript does not have a character type. To represent a character, make a string with just one character in it.

The escape sequences allow for inserting characters into strings that are not normally permitted, such as backslashes, quotes, and control characters. The \u convention allows for specifying character code points numerically.

"A" === "\u0041"

Strings have a length property. "seven".length is 5.

Strings are immutable. Once made, a string can never be changed. But it is easy to make a new string by concatenating other strings together with the + operator. Two strings containing exactly the same characters in the same order are considered to be the same string.

'cat' === 'c' + 'a' + 't'    // true

Strings have methods.

'cat'.toUpperCase()          // 'CAT'

Statements

A compilation unit contains a set of var statements and set of executable statements. The var statements define global variables. The statements execute in a context that has access to all of the global variables, including global variables that were defined in other compilation units. In web browsers, each <script> tag delivers a compilation unit that is compiled and immediately executed. Lacking a linker, JavaScript throws them all together in a common global namespace.

The var statement, when used inside of a function, declares the function's private variables. The var statement, when used outside of a function, declares global variables. Variables should be declared before they are used.

The switch, while, for, and do statements are allowed to have an optional label prefix that interacts with the break statement.

Statements tend to be executed in order, from top to bottom. The sequence of execution can be altered by the conditional statements (if and switch), by the looping statements (while, for, and do), by the disruptive statements (break, continue, return, and throw), and by function invocation.

A block is a set of statements wrapped in { } (curly braces). Unlike many other languages, blocks in JavaScript do not create a new scope, so variables should be defined at the top of the function, not in blocks.

The if statement changes the flow of the program based on the value of the expression. The then block is executed if the expression is truthy, otherwise the optional else branch is taken.

 The switch statement performs a multiway branch. It compares the expression for equality with all of the specified cases. The expression can produce a number or a string. When an exact match is found, the statements of the matching case clause are executed. If there is no match, the optional default clause is executed.

A case clause contains one or more case expressions. Tthe case expressions need not be constants. The statement following a clause should be a disruptive statement to prevent fall through into the next case. The break statement can be used to exit from a switch.

The while statement performs a simple loop. If the expression is falsy then the loop will break. While the expression is truthy, the block will be executed.

The for statement is a more complicated looping statement. It comes in two forms.

The conventional form is controlled by three optional clauses: the initialization, the condition, and the increment. First the initialization is done, which typically initializes the loop variable. Then the condition is evaluated. Typically, this tests the loop variable against a completion criterion. If the condition is omitted, then a condition of true is assumed. If the condition is falsy, the loop breaks. Otherwise the block is executed, and then the increment executes, and then the loop repeats with the condition.

The other form (called for in) enumerates the property names (or keys) of an object. On each iteration, another property name string from the object is assigned to the variable. It is usually necessary to test object.hasOwnProperty(variable) to determine if the property name is truly a member of the object or was found instead on the prototype chain.

for (myvar in obj) {
    if (obj.hasownProperty(myvar)) {
        …
    }
}

The do statement is like the while statement except that the expression is tested after the block is executed instead of before. That means that the block will always be executed at least once.

The try statement executes a block, and catches any exceptions that were thrown by the block. The catch clause defines a new variable that will receive the exception object.

The throw statement raises an exception. If the throw statement is in a try block, then control goes to the catch clause. Otherwise, the function invocation is abandoned, and control goes to the catch clause of the try in the calling function.

The expression is usually an object literal containing a name property and a message property. The catcher of the exception can use that information to determine what to do.

The return statement causes the early return from a function. It can also specify the value to be returned. If a return expression is not specified, then the return value will be undefined.

The break statement causes the exit from a loop statement or a switch statement. It can optionally have a label that will cause an exit from the labeled statement.

JavaScript does not allow a line end between the break and the label.

An expression statement can assign values to one or more variables or members, or can invoke a method, or can delete a property from an object. The = operator is used for assignment. Do not confuse it with the === equality operator. The += operator can add or concatenate.

Expressions

The simplest expressions are a literal value (such as a string or number), a variable, a built-in value (true, false, null, undefined, NaN, or Infinity), or an invocation expression preceded by new, or a refinement expression preceded by delete, or an expression wrapped in parentheses, or an expression preceded by a prefix operator, or an expression followed by

The ? ternary operator takes three operands. If the first operand is truthy, it produces the value of the second operand. But if the first operand is falsy, it produces the value of the third operand.

The operators at the top of the Operator Precedence list have higher precedence. They bind the tightest. The operators at the bottom have the lowest precedence. Parentheses can be used to alter the normal precedence, so

2 + 3 * 5 === 17
(2 + 3) * 5 === 25

The values produced by typeof are 'number', 'string', 'boolean', 'undefined', 'function', and 'object'.  If the operand is an array or null, then the result is 'object', which is wrong.

If the operand of ! is truthy, it produces false. Otherwise it produces true.

The + operator adds or concatenates. If you want it to add, make sure both operands are numbers.

The / operator can produce a non-integer result even if both operands are integers.

The && operator produces the value of its first operand if the first operand is falsy. Otherwise it produces the value of the second operand.

The || operator produces the value of its first operand if the first operand is truthy. Otherwise it produces the value of the second operand.

Invocation causes the execution of a function value. The invocation operator is a pair of parentheses that follow the function value. The parentheses can contain arguments that will be delivered to the function.

A refinement is used to specify a property or element of an object or array.

Literals

Object literals are a convenient notation for specifying new objects. The names of the properties can be specified as names or as strings. The names are treated as literal names, not as variable names, so the names of the properties of the object must be known in at compile time. The values of the properties are expressions.

Array literals are a convenient notation for specifying new arrays.

Functions

A function literal creates a function value. It can have an optional name that it can use to call itself recursively. It can specify a list of parameters that will act as variables initialized by the invocation arguments. The body of the function includes variable definitions and statements.

Sample Program

var make_tester = (function () {

// The make_tester function produces a tester object that can be used to test
// programs. It is called with one optional paramter that can customize the
// object.

// The function will have these methods:
//      assert(boolean, string)                         Pass if boolean is true.
//                                                      Returns a boolean.
//      test(expected, string, function, ...parameters) Pass if the function,
//                                                      when called with the
//                                                      parameters, produces
//                                                      the expected value.
//                                                      Returns a boolean.
//      pass(string)                                    Report pass, return true.
//      fail(string)                                    Report fail, return false.

    var default = {
        pass: 'Pass. {text}',
        pass: 'Pass. {text}',
    };

// The entityify, equal, and supplant functions will be shared by all
// instances produced by make_tester.

    function entityify(string) {

// Replace '&', '<', and '>' with HTML entities.
// This makes data safe for display in HTML.

        return string
             .replace(/&/g, "&amp;")
             .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;");
    }


    function equal(a, b) {

// Return a boolean depending on the equality of a and b.
// It returns true in the strange case when both a and b are NaN.

        return a === b || (typeof a === 'number' && isNaN(a) &&
                           typeof b === 'number' && isNaN(b));
    }


    function fill_in(template, string) {

// Replace '{text}' and with the entityified string.

        return string.replace(entityify(text));
    }


    return function make_tester(options) {

        function option(name) {
            var result;
            if (Object.isObject(options)) {
                result = options[name];
            }
            if (typeof result !== 'string') {
                result = default[name];
            }
            if (typeof result !== 'string') {
                result = '';
            }
            return result;
        }

        function pass(string) {
            var template = option('pass');
            if (template && string) {
                log(replace(template, string));
            }
            return true;
        }

        function fail(string) {
            var template = option('pass');
            if (template && string) {
                log(replace(template, string));
            }
            return false;
        }

        function assert(boolean, string) {
            return (boolean ? pass : fail)(string);
        }

        function test(expected, string, func) {
            var result = func.apply(null, arguments.slice(3));
            return assert(equal(expected, result), string);
        }

        return {
            assert: assert,
            test: test,
            pass: pass,
            fail: fail
        };
    };
}());