JavaScript - Web Developer Boot Camp

About this Article
Part I - Introduction to JavaScript
About JavaScript
JavaScript Implementations
Interpreted Programming Languages
Including JavaScript programs in Web Pages
Example JavaScript Programs
Part II - JavaScript (Pseudo) Reference
JavaScript Data Types
Type Conversions
Execution Contexts
JavaScript Expressions
JavaScript Operators
JavaScript Statements
JavaScript Native Objects
Links
Index

Part I - Introduction to JavaScript

About this Article

This article is intended to provide an introduction to JavaScript and a reference on the differences in the implementations of JavaScript in Mozilla and Microsoft Internet Explorer (MSIE). Examples which can be run directly from the article using Mozilla, Mozilla Firefox, Internet Explorer and Opera are used to illustrate general concepts as well as the use of each feature and Object in JavaScript. This is a work in progress and is provided in the current state in the hope that you will find it useful. I plan to continue work on this article in the hope it can become the definitive online resource for JavaScript. Email to feedback@bclary.com regarding this article is encouraged and welcome.

The article is organized into two parts.

Part I is intended as a general introduction to JavaScript. It is primarily targeted for beginning to intermediate level programmers but hopefully contains some information which will be useful for those with more advanced skills.

Part II serves as a reference for JavaScript.

Distinctive formatting is used for specific specialized topics:

Code samples and examples are presented in a monospace font. Variables are presented in an italic font in the text and as monospace italic in code samples.

Boxes with distinctive formatting are used to highlight specific sections.

Boxes with single line black borders are used to contain runnable examples.

Please note that the examples require the use of a pop-up window and you must enable pop-ups on this site in order to run them.

Boxes with double line red borders enclose notes which explain differences in how Mozilla and Internet Explorer implement JavaScript.

Boxes with notes.

Boxes with with todo notes.

Boxes indicating that the topic has yet to be written.

About JavaScript

JavaScript is a powerful, object-oriented programming language which, like Rodney Dangerfield, does not get the respect it deserves. It is available in stand-alone, open source implementations in C and Java for a variety of platforms from mozilla.org and as part of modern web browsers such as Mozilla, Mozilla Firefox, Internet Explorer, Opera and Safari. JavaScript is available on practically every computer world-wide.

JavaScript was created by Brendan Eich, then of Netscape and now with Mozilla Foundation, and was first introduced in the Netscape Navigator 2.0 web browser in early 1996. Originally the language was called LiveScript and was later renamed to JavaScript as part of a marketing effort of Netscape and Sun Microsystems although it has little to do with Java. Microsoft incorporated an implementation of JavaScript called JScript into Internet Explorer 3.

JavaScript's syntax resembles that of the computer languages C and Java although several of its features such as typeless variables, automatic semi-colon insertion, and automatic type coversions were designed to make it more accessible to non-professional programmers. Like C, the JavaScript language does not define any means of performing input and output and relies entirely upon its host environment (web browser) for such features. Unlike C++ or Java, JavaScript is not a strongly typed computer language nor does it currently support class-based object oriented programming but instead relies on the use of Prototypes which serve as templates for creating new objects.

JavaScript was standardized as ECMAScript in ECMA 262 in June 1997. A second edition of the standard was released in August 1998 which consisted primarily of editorial changes to the first edition. The most recent edition is ECMAScript Language Specification ECMA-262 3rd Edition (ECMAScript Language Specification ECMA-262 3rd Edition (Unofficial HTML version)) which was released in August 1998 and added a number of new features such as exception processing. JavaScript is an evolving language with future editions expected to include native XML processing ( ECMAScript for XML (E4X) Specification ), strongly typed variables, and class-based inheritance in JavaScript 2.0 and ECMAScript Language Specification 4th Edition (Proposed).

Any one who is familiar with C or Java, can easily learn JavaScript. Conversely, JavaScript can be learned as a first programming language and the skills transferred to programming in other languages such as C and Java.

JavaScript Implementations

Comparing the support for various implementations of different versions of JavaScript can be difficult due to the different versioning schemes used by Netscape and Microsoft. Netscape traditionally released different versions of their JavaScript interpreter to be associated with distinct script element language JavaScript versions such as JavaScript1.1 or JavaScript1.3 which did not necessarily map directly to an edition of the ECMA 262 standard. Microsoft used a different versioning scheme for JScript and only used the script language attribute in a very loose association with the actual JScript version.

JavaScript in Netscape Navigator, Mozilla and Mozilla Firefox

Netscape Navigator JavaScript versions
JavaScript version ECMA 262 Introduced
JavaScript 1.0 N/A Navigator 2.0
JavaScript 1.1 N/A Navigator 3.0
JavaScript 1.2 N/A Navigator 4.0-4.05
JavaScript 1.3 1st Navigator 4.06-4.7x

Mozilla and its family of browsers (Mozilla Firefox, Mozilla Application Suite, Netscape 6.x, Netscape 7.x, …) introduced support for JavaScript 1.5. Mozilla performs a partial emulation of earlier versions of JavaScript if the version is specified in the script element. For compatibility with other modern browsers, it is best to only specify the JavaScript language without version either through the language or type attributes.

Mozilla JavaScript versions
JavaScript version ECMA 262 Introduced
JavaScript 1.5 3rd Mozilla / Firefox / Netscape 6.x, 7.x, …

Guides and References for the various editions of JavaScript used in Netscape Navigator and Mozilla were available on Netscape DevEdge however are no longer available since the site was taken down by AOL. Copies of the Netscape JavaScript Guides and References can be found on the web, however they are not authorised.

JavaScript in Internet Explorer

A history of Internet Explorer is available from Microsoft. The mapping in the following table of JScript version to maximum supported JavaScript language version for each version of MSIE is based upon guess work since it is not possible to test multiple versions of MSIE on the same machine and there is a dearth of documentation available from Microsoft regarding JavaScript language versions. Feedback and corrections are welcome.

A list of feature availability for the various JScript versions is also available from Microsoft.

Guides and references for Internet Explorer's implementation of JavaScript are available from MSDN

Internet Explorer JScript versions
JavaScript version JScript version ECMA 262 Introduced
JavaScript 1.0 JScript 1.0 N/A MSIE 3.0
JavaScript 1.1 JScript 3.0 1st MSIE 4.0
JavaScript 1.3 JScript 5.0 3rd MSIE 5.0
JavaScript 1.3 JScript 5.1 3rd MSIE 5.01
JavaScript 1.3 JScript 5.5 3rd MSIE 5.5
JavaScript 1.3 JScript 5.6 3rd MSIE 6.0
N/A JScript 7.0 N/A .Net

Much of the information in this article regarding differences in the implementations of JavaScript in Mozilla and Internet Explorer were developed using mozilla.org's JavaScript Test Library.

Interpreted Programming Languages

JavaScript is an example of an interpreted programming language. Unlike other interpreted languages which compile (translate source code into machine code) each statement each time it is executed, JavaScript first compiles the entire JavaScript program before beginning to execute it. JavaScript also provides the ability to compile source code on the fly.

Interpreted computer languages have the advantage that they can be run in any environment so long as an interpreter program for that environment is available. A disadvantage of interpreted computer languages is the need to compile the programs each time they are run. Other examples of interpreted programming languages are Basic, Perl and Python. Python has the additional capability to save compiled programs to disk where they can be run later without having to be interpreted.

Including JavaScript programs in Web Pages

JavaScript programs can be run either from the command-line using a stand-alone JavaScript interpreter or executed in Web Pages using Web browsers. By far, the most common use of JavaScript is in web pages and all examples in this article will use such an approach.

Script programs are included into web pages through the use of the script element anywhere inside the HTML head or body elements of an HTML document. The program code can be included in the HTML document by placing it inside of the script element or by placing it in an external file and referencing the file through the src attribute of the script element. The language or type attributes of the script element can be used to specify the programming language and version the script is written. If no scripting language or version is specified, the web browser will use its default values which is typically the latest version of JavaScript the browser supports.

Specifying Script Language Versions

Script authors typically use the script language version to hide advanced scripts from older browsers which do not support the language features being used. This approach has some drawbacks since older browsers may still compile the script even if they do not execute it. This can lead to compile time errors for unsupported language features in older browsers such as Netscape Navigator 3.x and 4.x although this is less of a problem today since the market-share of these older browsers has diminished to insignificance.

There are two methods for specifing the language version in the script tag.

  1. specify the language and version in the language attribute of the script tag.

    <script language="javascript">
    // default version of javascript
    </script>
    
    <script language="javascript1.3">
    // javascript version 1.3
    </script>
    
  2. specify the language mime type and version in the type attribute in the script tag.

    <script type="text/javascript">
    // default version of javascript
    </script>
    
    <script type="text/javascript;version=1.3">
    // javascript version 1.3
    </script>
    

The Mozilla family of browsers (Mozilla Firefox, Mozilla Application Suite, …) up to Gecko 1.7 support JavaScript versions 1.1, 1.2, 1.3, 1.4 and 1.5 specified either as the language attribute or as the type attribute of the script tag. If a higher version is specified, the script is ignored. If no version is specified in the script element, Mozilla will default to JavaScript 1.5. An additional feature of Mozilla's current implementation is that it will emulate the features of the specified version of the language if the language version is specified. This can cause some browser-compatibility problems since Internet Explorer does not attempt such emulation. A change to Mozilla's implementation to not emulate older JavaScript versions is under consideration in Bugzilla 255895 although this change would not appear before Mozilla 1.8.

Internet Explorer 6 supports JavaScript versions 1.1, 1.2 and 1.3 specified as the language attribute and ignores scripts which specify a higher version. Internet Explore 6 only supports type="text/javascript" and ignores any other value of type which includes version or other information. Internet Explorer does not emulate the behavior of older versions of JavaScript when older versions are specified.

Opera 7.54 supports JavaScript versions 1.1, 1.2, 1.3, 1.4, 1.5 when specified as the language attribute. Opera will execute any JavaScript language version if it is specified in the type attribute.

Konqueror 3.2.1 will execute any version of JavaScript when specified as the language attribute or the type attribute.

Work is underway to develop the next generation of JavaScript, JavaScript 2.0, which will introduce many new advanced features to the language. When an implementation of JavaScript 2.0 becomes available, the proper use of the script element language version should be able to hide the new scripts from older versions of Mozilla and Internet Explorer although other browsers such as Opera and Konqueror may have problems.

Inline JavaScript Examples

<html>
  <head>
    <script language="javascript">
      // inline JavaScript code here
    </script>

    <script language="javascript1.3">
      // inline JavaScript 1.3 code here
    </script>

    <script type="text/javascript">
      // inline JavaScript code here
    </script>

    <script type="text/javascript;version=1.3">
      // inline JavaScript 1.3 code here
    </script>
  </head>
  <body>
    stuff
  </body>
</html>

External JavaScript Examples

<html>
  <head>
    <-- external JavaScript code in file somefileuri -->
    <script language="javascript" src="somefileurl" ></script>

    <-- external JavaScript 1.3 code in file somefileuri -->
    <script language="javascript1.3" src="somefileurl" ></script>

    <-- external JavaScript 1.3 code in file somefileuri -->
    <script type="text/javascript" src="somefileurl" ></script>

    <-- external JavaScript 1.3 code in file somefileuri -->
    <script type="text/javascript;version=1.3" src="somefileurl" ></script>
  </head>
  <body>
    stuff
  </body>
</html>

Note the use of HTML comments

<-- … -->      

inside of the HTML document and the use of single line JavaScript comments

// …

inside of the script element. An HTML comment prevents its contents from being displayed by a web browser while a JavaScript comment prevents the JavaScript interpreter from attempting to compile and execute the line. Comments are typically used for communicating with other web developers who read the source code of a web document or JavaScript program.

Hiding JavaScript from Non-scriptable browsers

The HTML 4.01 specification states that if a web brower does not recognize an HTML element in a document, it should attempt to render the contents of the element. This can cause some browsers which do not support the script element to display inline JavaScript programs as text in a web page. A standard technique to hide JavaScript code from such browsers is to enclose inline JavaScript inside of HTML comments as in the following example:

<script type="text/javascript">
<--
// inline javascript code 
//-->
</script>

The <-- … --> hides the script from non-scriptable browsers while the last line comment // hides the end of the HTML comment --> from the JavaScript interpreter. Other techniques involving CDATA sections are used for hiding inline scripts in XHTML or XML documents.

A common error by those who do not understand HTML and JavaScript is to wrap JavaScript code in external JavaScript files inside of HTML comments. The only reason to use HTML comments inside of a script element is to hide the inline script from non-scriptable browsers which do not recognize the script element. If a script is contained in an external file, a non-scriptable browser will not even attempt to load the file. There is no reason to include such HTML comments in an external file and it is technically an error to do so although most browsers are forgiving of this common beginner's mistake.

Example JavaScript Programs
Hello World!

Ever since Kernighan and Ritchie's The C Programming Language (K&R) was first published in 1978, the standard first program in any language is one that prints the message hello, world. Since this article is inspired by K&R our first JavaScript program will do the same.

"hello world" can be written in a web page as:

<html>
<head>
<script type="text/javascript">
document.write('hello, world');
</script>
</head>
<body>
<h1>The Hello World JavaScript Program</h1>
</body>
</html>

To run the program, create a document containing the above text, then open the web page with Mozilla or Internet Explorer which will display

The Hello World Program

hello, world

The actual JavaScript program consists of the statement

document.write('hello, world');

Unlike C there is no preferred main function where execution of the program begins. In JavaScript, the source code is first compiled, then each global statement is executed in turn. Web browsers and HTML provide other means to begin execution of JavaScript depending upon events in the browser but will not be covered in this article.

Let's pick the "hello, world" program a part and look at its pieces

document.write('hello, world') is a function call which calls a method (function) write of the object document with argument 'hello, world'.

document is a host object provided by the web browser and document.write is a function property (method) of the document object which outputs text in a web page. document and document.write are not official parts of the JavaScript language, but are supplied by the web browser as part of its Document Object Model (DOM). We will not be discussing the Document Object Model in this article instead focusing our attention on the JavaScript language itself. If you are already familiar with C, you may consider the DOM to be an external library provided by the web browser.

'hello, world' is an example of a literal primitive string value. Literal primitive string values are sequences of characters which are surrounded by either single quotes (') or double quotes (").

The function call document.write('hello, world') is an example of an expression. The terminating semi-colon (;) terminates the statement composed of the expression.

Examples in this article

The examples in this article are written in such a fashion that they can be executed directly from the article itself. The examples use a user-defined function named msg which uses the DOM to output strings to web pages.

msg is defined as:

function msg(s)
{
  document.write(s + '<br>');
}

When a function call msg(arg) is performed, the body of the function msg ( the statements inside of the braces { and }) are executed with the value of the argument variable s set to the value of the variable arg.

document.write writes the argument s followed by the HTML tag <br> to the output document where it is displayed by your web browser.

Each example will consist of the JavaScript source code followed by an HTML select element which allows the choice of JavaScript version to be used when executing the example and an HTML button element which will open a new browser window and execute the example code. The new window will display the source code of the example, followed by the output. Note that the source code for the function msg is not displayed for brevity's sake.

If you have a popup blocker enabled, you must configure it to allow this site to open popup windows.

The "Hello World" program would appear as:

Example Hello_World!
msg('hello, world');

Run this example by selecting the JavaScript version and then clicking the execute button.

A slightly more realistic example.

Our next example program is a slightly more realistic program based upon K&R's Fahrenheit to Celsius conversion program and introduces a number of JavaScript features which are found in all JavaScript programs.

Example Fahrenheit_to_Celsius
/*
* Display Fahrenheit to Celsius Conversion table
* for 0°F to 100°F in steps of 10°F.
*/
var lower = 0;    // lower limit of Fahrenheit temperature
var upper = 100;  // upper limit of Fahrenheit temperature
var step  = 10;   // increment of Fahrenheit temperature
var fahrenheit;   // current Fahrenheit temperature
var celsius;      // current Celsius temperature

fahrenheit = lower;
while (fahrenheit <= upper)
{
  celsius = Fahrenheit2Celsius(fahrenheit); 
  msg(fahrenheit + '°F is ' + celsius + '°C');
  fahrenheit = fahrenheit + step;
}

function Fahrenheit2Celsius(fahr)
{
  var cels = (5/9)*(fahr - 32);
  return cels;
}

The program begins with a multiple line comment which describes the purpose of the program.

/*
* Display Fahrenheit to Celsius Conversion table
* for 0°F to 100°F in steps of 10°F.
*/

Comments are text which are intended to be read by programmers trying to understand how a program work. They are ignored by the JavaScript interpreter.

Multiple line comments begin with /* and end with */ and are useful in circumstances when a single comment line is insufficient or when you would like to comment out a portion of the program so that the JavaScript interpreter will ignore it.

Note that multiple line comments can not nest. For example

/* this /* is an invalid */ comment */

For this reason, many people use single line comments inside of functions, so that if it is desired to comment out the entire function later, a single /* … */ can be placed around the entire function. If multiple line comments had been used inside of the function, this would not have been possible.

The next 5 lines of the program contain statements which declare the variables lower, upper, step, fahrenheit, celsius as global variables.

var lower = 0;    // lower limit of Fahrenheit temperature
var upper = 100;  // upper limit of Fahrenheit temperature
var step  = 10;   // increment of Fahrenheit temperature
var fahrenheit;   // current Fahrenheit temperature
var celsius;      // current Celsius temperature

A variable is a name for a data item in a program and is an example of an identifier. An identifier is a sequence of characters beginning with either $ (dollar sign), _ (underscore) or a unicode letter followed by unicode letters, unicode digits, underscores (_) or dollar signs ($). Note that the use of unicode allows the creation of variable and function names in character sets other than latin.

These variables are global because they were declared outside of any function definition and thus are available everywhere in the JavaScript program. In JavaScript variables do not have to be declared before use but it is recommended. JavaScript variables, unlike C or Java, do not have declared data types. A variable in JavaScript can hold any type of data.

Each of the variable declarations is followed by a C++ style single line comment of the form // …. Single line comments begin with // and end at the end of the line where they appear and are ignored by the JavaScript interpreter. They are extremely useful for attaching a descriptive note to a single line of code.

The variable declarations for lower, upper and step include initializers which set the initial values of the variables to primitive number values 0, 100 and 10 respectively. The variable declarations for fahrenheit and celsius do not include intializers which means they have the value undefined as their initial values.

The next statement

fahrenheit = lower;

assigns the value of the variable lower to the variable fahrenheit using the assignment operator =.

The next statement is a while statement which has the general form:

while (condition)
  statement

while first evaluates condition as a primitive boolean value (true or false) and will execute statement so long as condition is true. If condition is initially false, statement will not be executed. while is an example of an iterative or looping statement. Other examples of iterative statements in JavaScript are for and do while.

Our while statement looks like:

while (fahrenheit <= upper)
{
  celsius = Fahrenheit2Celsius(fahrenheit);
  msg(fahrenheit + '°F is ' + celsius + '°C');
  fahrenheit = fahrenheit + step;
}

The condition is fahrenheit <= upper. <= is a comparison operator which returns true when the left operand ( fahrenheit in our example ) is less than or equal to the right operand ( upper in our example ).

The statement is the block statement

{
  celsius = Fahrenheit2Celsius(fahrenheit);
  msg(fahrenheit + '°F is ' + celsius + '°C');
  fahrenheit = fahrenheit + step;
}

consisting of all statements between the braces { and }.

This while statement generates the conversion table by repeatedly executing (looping over) the set of statements contained in the block statement as long as the condition fahrenheit <= upper is true.

The three statements inside of the block statement of the while:

  1. call the function Fahrenheit2Celsius with the value of the argument fahr set to the value of the variable fahrenheit then set the value of the variable celsius to the return value of the function.

  2. output a message by calling the function msg with the value of the argument set to a primitive string consisting of the concatenation of the fahrenheit value, the string value '°F is ', the celsius value and the string value '°C'. JavaScript creates this string value by automatically converting the primitive number values in fahrenheit and celsius to string values and the applying the string concatenation operator +. Note that this automatic conversion behavior is dramatically different from other languages.

  3. increment the value of the fahrenheit variable by the value of the variable step.

Note that the while loop will terminate as soon as fahrenheit is greater than the variable upper.

The final part of the program is the definition of the function Fahrenheit2Celsius with argument fahr.

function Fahrenheit2Celsius(fahr)
{
  var cels = (5/9)*(fahr - 32);
  return cels;
}

The body of the function consists of the two statements contained within the braces { and }. Each time the function is called, the argument is initialized to the value passed by the caller and the body of the function is executed. The return value of the function is used as the value of the function in whatever expression the function call occured.

The first statement of Fahrenheit2Celsius declares the variable cels in the scope of the function which is initialized by the value of the expression (5/9)*(fahr - 32). The expression (5/9)*(fahr - 32) is evaluated by first calculating the contents of the first parentheses (5/9) by dividing the number 5 by the number 9, then calculating the value of the second parentheses (fahr - 32) by subtracting the number 32 from the value in the variable fahr, then multiplying the two results together. Note that JavaScript automatically converts the result of dividing two integers into a floating point number unlike C. The next statement returns the value of the variable cels as the value of the function.

The scope of the function determines how the values of variables are determined inside the function. When a function is called, its scope consists of the variable (or variables) defined as arguments to the function along with the variables declared inside of the function. Whenever an expression in the function refers to a variable, JavaScript first tries to find the variable in the function scope and if it is found, the value of that variable is used. However if the variable is not found in the function's scope, JavaScript will attempt to find the variable in the parent scope of the function. In our example, the parent scope of the function Fahrenheit2Celsius is the global scope of the program. The parent scope of a function is determined at compile time and does not change regardless of the scope where the function is executed. Once the function has completed executing, any variables defined in the scope of the function will cease to exist.

If a variable is used inside of a function without being declared using the var statement, JavaScript considers the variable to part of the program's global scope. Declaring function variables helps isolate functions from side effects in programs and helps increase maintainability in programs. For example, the Venkman JavaScript debugger, available from mozilla.org, will display all variables declared in function scope in a separate "local variables" panel from the "global variables/properties". Considering the large number of global variables and properties which are defined by the browser's DOM, it is much easier to inspect the variables used in a function if they are declared as local.

Note that JavaScript does not require that a function be declared or defined before it is used in a program. The function Fahrenheit2Celsius could have been located anywhere in the program.

Introduction to Objects

Properties

JavaScript objects are named collections of properties. Properties have names and can contain primitive values such as strings, numbers or references to other Objects. C++ and Java programmers can think of a JavaScript object as similar (in their use) as an instance of a struct or class. JavaScript objects can be created either by using literal object initializers using braces ({}) or using the new operator on constructors.

For example, the following creates an empty object literalObject using an literal object initializer and another empty object constructedObject using the new operator on the Object() constructor.

var literalObject = {};
var contructedObject = new Object();

Properties are set and retrieved using the member of operators (.) or ([]). If variable myobject references an object, then the property named propname can be accessed in one of two ways:

  1. myobject.propname
  2. myobject['propname']

where propname is some sequence of characters. The only difference in these two approaches is the first (myobject.propname) requires that propname be an identifier, that is the characters in propname must begin with a unicode letter, an underscore (_) or a dollar sign ($) and the remaining characters must be unicode letters, unicode digits, underscores or dollar signs.

If propname is not an identifier, the second syntax (myobject['propname']) can still be used. For example myobject['this is a property name that is not an identifier'] is a valid property reference. The second syntax can also be used with a variable containing the property name (object[prop]) which is useful in circumstances where the property name is not known until the program runs.

Local versus Shared Properties

Every JavaScript object has a special internal property called its prototype object which is used to implement shared properties and object inheritance. To understand the role of the prototype object a little better, lets look at how JavaScript determines the value of an object's property.

When you access the value of an object's property myobject.propname, JavaScript first looks in myobject for a local property named propname. If a local property with the requested name is found, JavaScript will return the value of that property. If the property is not found, JavaScript will try to find the property in the object's prototype object. If again the property is not found, JavaScript will attempt to find the property in the prototype of the prototype and so on until either the property is found or the prototype chain ends. If the property was not found, then JavaScript will return undefined as the result.

As a result, JavaScript objects which share prototype objects effectively share the properties of the prototype (and those of the entire prototype chain).

A local property is defined when you assign a value to an object property as in myobject.propname = value;. The value of this property is not shared with any other instances of objects. If a property is shared via the prototype chain, any assignment to the local property shadows the shared property effectively replacing it for that object.

Literal Object initializers can be used to define local properties and their initial values by listing each property name followed by a colon (:), followed by the property value as in

var literalObject = { property1: 'value1',
                      'property 2': 'value2' };

Each property/value pair (except the last) is terminated by a comma (,). Note that property names which are not identifiers (property 2 in the above example) can be written as string literal values.

Example Literal Object Properties
// create an instance of Object using a literal initializer
var literalObject = {
  property1: 'value1',
  'property 2': 'value2'
};

// display the values of the properties
msg('literalObject.property1 = ' + literalObject.property1);
msg('literalObject[\'property 2\'] = ' + literalObject['property 2']);

To create a similar object using the Object() constructor, we would first create the object using new Object(), then create the local properties by assigning values to them as in:

Example Constructed Object Properties
// create an instance of Object using a Constructor
var constructedObject = new Object();

// add properties to object
constructedObject.property1     = 'value1';
constructedObject['property 2'] = 'value2';

// display the values of the properties
msg('constructedObject.property1 = ' + constructedObject.property1);
msg('constructedObject[\'property 2\'] = ' + constructedObject['property 2']);

As you can see, the only difference in these examples is the means by which the objects were created.

Simple Object methods

Object properties are not limited to simple values such as strings or numbers but can also be functions which are also known as methods. For example, we can create an object which represents a circle which can report its area.

Example Simple Circle
// define the method getArea
function getArea()
{
  return Math.PI * this.radius * this.radius;
}

// create a 'circle' with radius 1
var circle = {radius: 1};

// attach the method to the circle object 
// as a local property
circle.getArea = getArea;

msg('circle with radius ' + circle.radius + 
    ' has area ' + circle.getArea());

This program first defines a function getArea which will be used as a method of the circle object. getArea returns the value of area of the circle by calculating the square of the circle's radius multiplied by π. this is a special name which is used inside of methods to refer to the object which contains the method. Inside of the getArea method, this.radius refers to circle.radius. Math is a built-in JavaScript object which contains a number of properties and methods useful in mathematical calculations. Math.PI is the value of the mathemetical constant PI (π).

The next statement creates the circle object via an object initializer to contain a numeric property called radius representing a radius of the circle.

The next statement creates a local property of the circle object getArea by assigning a reference to the function getArea.

Simple Constructors

The simple approach to creating and using JavaScript objects is useful when you have only a few objects with a small number of properties each but can be awkward when you have more objects to create. Consider the situation where you have many instances of the same kind of object to create:

function getArea()
{
  return Math.PI * this.radius * this.radius;
}

var circle1 = {radius: 1};
circle1.getArea = getArea;

var circle2 = {radius: 2};
circle2.getArea = getArea;

var circle3 = {radius: 3};
circle3.getArea = getArea;

…

The repetitive creation and initialization of the properties and methods of the various circle objects is boring and error prone. Fortunately, JavaScript provides the ability to encapsulate the creation and initialization of similar instances of objects through the use of constructors.

Example Simple Constructor
function Circle(radius)
{
  this.radius = radius;
  this.getArea = function () 
                 {
                   return Math.PI * (this.radius * this.radius); 
                 };
}

// create an array to hold the circle objects
var circles = [];
var i;

// loop from i == 0 to 2 creating Circle objects
for (i = 0; i < 3; i++)
{
  circles[i] = new Circle(i + 1);
}

for (i = 0; i < 3; i++)
{
  msg('The area of a circle of radius ' + 
      circles[i].radius + ' is ' + circles[i].getArea());
}

The function Circle defines a constructor for Circle objects. It takes one argument, radius, which is a number representing the radius of the circle.

The next statement uses an array initializer to create an empty Array object called circles. An Array is a kind of JavaScript object used to store lists of items which can be accessed by using the [] member of operator and the numeric position (index) of the item in the list. Items in Arrays are indexed from 0. For example, if list is an Array, then list[0] is the first item in the list, list[1] is the second item, and so on.

The for loop is very similar to the while loop we saw in the Fahrenheit conversion example and is used to create 3 instances of the Circle object which are stored in the circles array.

for loops have the form:

for (initializer; conditional; increment)
  statement

and are equivalent to the following while loop:

initializer;
while (conditional)
{
  statement
  increment;
}

The initializer expression is evaluated first. It is used to set up the initial values before the loop is executed. Then the conditional expression is evaluated. If it is false, the for loop terminates and the statement following it in the program is executed. If the condition is true, the statement is executed and the initializer expression is evaluated and the whole process begins again by testing if the conditional is still true.

The new Circle(radius) statement creates an instance of the Circle object by creating an empty native JavaScript object, then setting its prototype object to the prototype of the function Circle, then calls the Circle constructor with the this identifier set to reference the newly created object. The constructor adds the local properties radius and getArea to the instance. getArea is initialized with a function expression which can be called like any other function.

Since the properties radius and getArea were created as local properties of the Circle instance, they are created independently for each instance of Circle. Even though each instance of Circle has the same method getArea, the compiled code is duplicated for each separate instance thus increasing the memory usage if there are many such instances created. We could have saved the extra code by defining the function separately and simply assigning a reference to the function to getArea however that would have still meant we needed an extra local property for getArea in each instance. We will see later how to save both the compiled code and the extra reference when we discuss object prototypes in more detail.

Finally, the program outputs a message by concatenating the string value 'The area of a circle of radius ', the value of the radius property of the Circle instance, the string ' is ' and the value returned by calling the method getArea of the Circle instance.

Note that constructor functions such as Circle() should not be called as ordinary functions unless they are specifically designed to be called that way. The reason has to do with the value of the this object reference inside of normal function calls does not reference the object you expect. For more details see Execution Contexts.

Object Inheritance

The style of creating objects using Simple Constructors is sufficient for most cases however it fails to handle cases where different kinds of objects need to share properties and methods. What is needed is a way for us to create objects which share properties and methods. What we need to do is combine the use of constructors and prototypes.

Remember, constructors are functions (and also objects) which the new operator acts upon to create instances of the object defined by the constructor.

Since constructors are objects, constructors also have a prototype property which is conveniently named prototype. When the new operator acts upon a constructor, it first creates an empty native JavaScript object (called the instance), then sets the internal prototype property of the instance to the prototype property of the constructor, then the identifier this is set to point to the new instance and the constructor is called. The constructor can create local properties of the newly created object by creating the properties on the this object.

It is possible to create chains of constructors where the prototype of one constructor is an instance of another constructor. JavaScript uses these prototype chains to implement object-oriented inheritance.

Lets generalize our Circle object to be a part of a graphics program where we use families of objects to represent geometric shapes.

Example Object_Inheritance
/*
* Circles and Squares
*/

// Define a Shape Object which is intended to serve as the ancestor
// of all "shapes" in the program.
function Shape(size)
{
  if (size > 0)
  {
    // only define the size property as a local property 
    // of each instance if it is non-zero. Otherwise, the 
    // shared size property of the Shape Object's prototype 
    // object will be used.
    this.size = size;
  }
}

// Add a shared sized property to Shape's prototype
// Every instance of Shape has a default size of 0
// unless it is overridden by the constructor.
Shape.prototype.size = 0;

// Every instance of Shape has the same name. Implement it
// as a shared property so that only one instance of the name
// can be shared amongst all instances.
Shape.prototype.name = 'Shape';

// Every instance of Shape has an area which scales as the 
// square of the size of the shape. Define a default getArea
// method which can be shared or overridden by child classes.
Shape.prototype.getArea = function _getArea()
{
  return this.size * this.size;
}

/*
 * Squares
 */
// Define a Square as a kind of Shape
function Square(size)
{
  // call the Shape constructor on this
  // object to initialize it
  Shape.call(this, size);
}

// set Square's prototype to Shape to
// share Shape's properties
Square.prototype = new Shape;

// override the shared name property
Square.prototype.name = 'Square';

// Note that Square does not need to 
// override Shape's getArea method

/*
 * Circles
 */
// Define Circle as a kind of Shape
function Circle(size)
{
  // call the Shape constructor on this
  // object to initialize it
  Shape.call(this, size);
}

// set Circle's prototype to Shape to
// share Shape's properties
Circle.prototype = new Shape;

// override the shared name property
Circle.prototype.name = 'Circle';

// override the getArea method to return the 
// proper area of a Circle
Circle.prototype.getArea = function()
{
  return Math.PI * Shape.prototype.getArea.call(this);
};

function tellMeAbout(shape)
{
  var list = '';
  for (var propname in shape)
    list += propname + ', ';

  msg(shape.name + ' has the following properties: ' + list);

  msg('shape ' + 
      ('size' in shape ? ' has ' : ' does not have ') + 
      'property size');
 
  msg('shape ' + 
      (shape.hasOwnProperty('size') ? ' has ' : ' does not have ') + 
      'local property size');
  
  msg('shape ' + 
      ('name' in shape ? ' has ' : ' does not have ') + 
      'property name');
  
  msg('shape ' + 
      (shape.hasOwnProperty('name') ? ' has ' : ' does not have ') + 
      'local property name');
  
  msg('shape ' + 
      ('getArea' in shape ? ' has ' : ' does not have ') + 
      'property getArea');
  
  msg('shape ' + 
      (shape.hasOwnProperty('getArea') ? ' has ' : ' does not have ') + 
      'local property getArea');
  
  msg('shape ' + shape.name + ' ' + 
      (shape instanceof Object ? 'is' : 'is not') + 
      ' an instance of Object');
  
  msg('shape ' + shape.name + ' ' + 
      (shape instanceof Shape ? 'is' : 'is not') + 
      ' an instance of Shape');
  
  msg('shape ' + shape.name + ' ' +
      (shape instanceof Circle ? 'is' : 'is not') + 
      ' an instance of Circle');
  
  msg('shape ' + shape.name + ' ' +
      (shape instanceof Square ? 'is' : 'is not') + 
      ' an instance of Square');
  
  msg('The area of a ' + shape.name + ' of size ' + 
      shape.size + ' is ' + shape.getArea());
}
var shape;

msg('<br>create an instance of Shape with no size<br>');

shape = new Shape;

tellMeAbout(shape);

msg('<br>create an instance of Circle with size 1<br>');

shape = new Circle(1);

tellMeAbout(shape);

msg('<br>create an instance of Square with size 2<br>');

shape = new Square(2);

tellMeAbout(shape);

This example is quite a bit longer than we have seen so far however it is really not any more complicated. There are four sections to the program:

  1. Definition of the Shape Object.
  2. Definition of the Square Object as a kind of Shape.
  3. Definition of the Circle Object as a kind of Shape.
  4. Creation of instances of Square and Circle and the output of messages

In the first section of the program, the Shape constructor is defined as a function which takes one argument: the size of the object in some unit of measure. The body of the Shape constructor consists of an if statement. if statements are used to select which set of statements are to be executed depending on the value of a conditional test and have the form:

if (condition)
  statement

If condition evaluates to true, the statement will be executed, otherwise it will be skipped. Another form allows the choice of one of two possible statements depending on the condition.

if (condition)
  statement1
else
  statement2

In this case, if condition evaluates to true, statement1 will be executed, but if condition is false, then statement2 will be executed.

In our example, the condition is the test size > 0. If the size is greater than 0, the set of statements in the block ( the statements surrounded by the braces {} ) is executed. If the size is less than or equal to 0, the local property this.size is not defined in order to allow it to be shared as the 0 value. Since in our example a Shape of 0 size doesn't make much sense the trick doesn't add much to our example, but does illustrate a technique where you can save memory usage by sharing the most common value of a property and only defining the property as local if the value differs.

Immediately following the Shape constructor, the shared size property is added to Shape's prototype object initialized to 0.

In order to allow our Shapes to know what kind of shape they are, the next statement adds a shared property name with value 'Shape' to each instance of the Shape object. Note that even if we create 100,000 Shapes, no additional memory will be required to store the Shapes names since each will share the name property.

As the final part of the definition of Shape objects, a shared method getArea is defined. Since areas scale as the square of the size of an object, I went ahead and defined the shared method as such.

The second section of the program defines the Square Objects. The constructor Square is defined to take the same argument as the Shape constructor. In order to re-use the initialization code in Shape, the call method of Function objects is used to call Shapes constructor. call allows us to set the this value to point to our newly created Square while passing any required arguments.

Following the definition of the Square constructor, the prototype property of Square is initialized to be an instance of the Shape Object. This step is what makes the sharing of properties and methods between Squares and Shapes possible. If a property is not found as a local property of a Square, Square's prototype is search for the property and so on.

Next the name property is overridden since we want our Squares to know they are Squares and not just Shapes.

Since the area of a square is exactly the square of the length of its sides, there is no need to override the getArea method inherited from Shape.

The third section creates the Circle Object in a very similar fashion to that used to define Squares. The only difference in the overriding of the getArea method to apply the correct forumula for the area of a circle.

The fourth section of the program creates instances of Shape, Circle and Square and generates various reports about them. To simplify the program, a function tellMeAbout is defined to take an argument shape and then report various items about the shape such as:

  • list of enumerable properties in an object
  • whether properties exist in objects
  • whether properties are local or shared
  • whether an object inherits from a particular Constructor
  • the area of the shape

tellMeAbout uses the operator in which tests if a property exists in a object either as a local property or as a property found in the object's protocol chain. For example:

'propname' in object

will return true if object.propname exists.

The operator in can also be used in a for loop to enumerate each of an object's properties so long as the properties do not have the internal DontEnum attribute. For example, to iterate over the list of enumerable properties in an object:

var prop;
for (prop in object)
{
  // prop is a string value 
  // containing the name of a property
}

The member function hasOwnProperty of Function objects, is used to test if a property is local or shared. object.hasOwnProperty(propname) returns true if propname is a local property of object.

tellMeAbout also uses the instanceof operator to test if an instance of an object is an instance of a particular constructor. For example:

object instanceof SomeConstructor

A new type of expression called the ternary or conditional expression is used throughout the function tellMeAbout. The conditional expression looks like:

condition ? expression1 : expression2

The value of the conditional expression is the value of expression1 if the condition evaluates to true. If condition is false, the value of the conditional expression is the value of expression2. This operator is convenient shorthand for:

var value;
if (condition)
  value = expression1;
else
  value = expression2;

Part II - JavaScript (Pseudo) Reference

JavaScript Data Types

Data types in JavaScript are divided into two categories:

  1. Primitive types whose members are primitive values. The primitive types in JavaScript consist of Undefined, Null, Boolean, Number and String.

  2. Object types whose members are all objects. A JavaScript object is really just an unordered collection of properties which may have attributes governing how the properties behave.

Even though there is a one-one correspondence between some of the primitive types and some Object types, they are not the same.

Undefined

The Undefined primitive type has only one value: undefined which is used to represent the value a variable contains when it has not been initialized.

Null

The Null primitive type has only value: null. While null and undefined are used in similar circumstances, the primary difference is that if a variable which has value null has been intentionally initialized to contain a value whereas an undefined value can mean the variable is uninitialized or even does not exist at all.

Boolean

The Boolean primitive type has two values: true and false. Boolean primitive values are not the same as instances of Boolean Objects.

String

The String primitive type are sequences of characters. String primitive values are not the same as instances of String Objects.

Literal primitive string values are written as a sequence of characters surrounded either by single quotes (') or double quotes ("). For example, "this is primitive string" and 'this is primitive string' are both primitive string values.

To include quotes in a string literal, you can alternate the type of quote as in "this contains a single ' quote" or you can use character escapes to temporarily change the quote to a normal character as in 'this contains a single \' quote'.

Character escapes are a means of temporarily changing the meaning of a character and are used to describe control characters as well as all quotes to be included in literal string. A character is escaped by preceding it with a \ character, for example to escape the letter a, you would write it as \a. Section ECMAScript 7.8.4 String Literals describes the character escapes \' (escaped single quote), \" (escaped double quote), \\ (escaped escape character), \b (backspace), \f (form feed), \n (newline), \r (carriage return), \t (tab), \v (vertical tab) which allow special characters to be included in string literals.

MSIE does not support the \v vertical tab character in literal strings. Since \v is defined to be a white space character in Section 7.2 of the ECMAScript standard, MSIE also fails white space handling involving \v.

Example Character Escapes

MSIE does not recognize vertical tab '\v' in strings.

msg('\' supported ' + (String.fromCharCode(39) == '\''));
msg('\" supported ' + (String.fromCharCode(34) == '\"'));
msg('\\ supported ' + (String.fromCharCode(92) == '\\'));
msg('\b supported ' + (String.fromCharCode(8) == '\b'));
msg('\f supported ' + (String.fromCharCode(12) == '\f'));
msg('\n supported ' + (String.fromCharCode(10) == '\n'));
msg('\r supported ' + (String.fromCharCode(13) == '\r'));
msg('\t supported ' + (String.fromCharCode(9) == '\t'));
msg('\v supported ' + (String.fromCharCode(11) == '\v'));
Number

The Number primitive type are the lowest level representation of integers and floating point numbers. Number primitive values are not the same as instances of Number Objects.

Literal primitive number values can be written as integers (123), as floating point with decimals (123.456), as floating point with exponents (123.456e10, the e may be either case), as hexadecimal integers (0xFF, the x or hex digits A-F may be either case)

Objects

As I already mentioned, objects in JavaScript are collections of unordered properties. Each property of an object has a set of internal (not directly accessible to JavaScript programs) attributes which control how the property can be accessed: DontDelete, ReadOnly, and DontEnum.

DontDelete
the property is permanent and can not be removed from the object using the delete operator. Any attempt to delete the property is ignored without error.
DontEnum
the property is not listed when the in operator is used in a for loop to enumerate properties of an object. For example,
for (var propname in object) { … }

will not list the property if it is DontEnum. However the in operator can be used to test if the property exists. For example,

('propname' in object)

will return true if object.propname exists and false otherwise.

ReadOnly
the property can not be changed through assignment and any attempt to assign to it is ignored without error.

When JavaScript1.1 or JavaScript1.2 are used in Mozilla, attempting to delete a {DontDelete} property or attempting to change a {ReadOnly} property will throw an error.

try
{
  Math.PI = 3;
  msg('Math.PI == ' + Math.PI);
}
catch(e)
{
  msg('Error assigning to a [ReadOnly] property. ' + 
      e.name + ': ' + e.message);
}
try
{
  delete Math.PI;
  msg('Math.PI == ' + Math.PI);
}
catch(e)
{
  msg('Error deleting a [DontDelete] property. ' +  
      e.name + ': ' + e.message);
}
Type Conversions

JavaScript automatically converts primitive values and object instances from one type to another depending upon the context. For example, as we have seen, when a number is added to a string using the + operator, JavaScript will determine that the appropriate operator is the string concatenation operator and will convert the number to a string before performing the operation.

input To Boolean To Number To String To Object
Undefined false NaN 'undefined' throw TypeError
Null false +0 'null' throw TypeError
Boolean no conversion 1 if input is true, +0 if input is false 'true' if input is true, 'false' if input is false new Boolean(input)
Number false if input +0, -0, or NaN otherwise true no conversion 'NaN' if input is NaN
'0' if input is +0, -0
'Infinity' if input is Infinity
otherwise a string primitive value consisting of the literal representation of the input value
new Number(input)
String false if string is empty, otherwise true NaN if the input does not match a literal number value, otherwise the number represented by the equivalent literal number value. no conversion new String(input)
Object true convert the object's default value to a number convert the object's default value to a string no conversion

Type Conversions to primitive types can be performed by using the constructors of the Native Object types as functions rather than as constructors. For example:

// Convert undefined to primitive values
msg('Boolean(undefined) is ' + Boolean(undefined));
msg('Boolean(null)      is ' + Boolean(null));
msg('Boolean(10)        is ' + Boolean(10));
msg('Boolean("42x")     is ' + Boolean("42x"));
msg('Number(undefined)  is ' + Number(undefined));
msg('Number(null)       is ' + Number(null));
msg('Number(10)         is ' + Number(10));
msg('Number("42x")      is ' + Number("42x"));
msg('String(undefined)  is ' + String(undefined));
msg('String(null)       is ' + String(null));
msg('String(10)         is ' + String(10));
msg('String("42x")      is ' + String("42x"));

One surprising result of the Object to Boolean conversion is that an instance of the Boolean Object with value false evaluates to true in conditional expressions but the Object to String conversion of the instance is the string 'false'.

var bool = new Boolean(false);
if (bool)
{
  msg('new Boolean(false) is true');
}
else
{
  msg('new Boolean(false) is false');
}

msg('String(new Boolean(false)) is ' + String(bool));

In Mozilla (JavaScript1.1, JavaScript1.2), new Boolean(false) is converted to false instead of true

When called as a function, the Number constructor attempts to convert its argument to a number value.

Mozilla JavaScript1.2 converts an Array object to its length. Mozilla JavaScript1.1, JavaScript1.3-JavaScript1.5 converts an empty Array to 0, an Array with one element to 1 and a non-empty Array with length greater than 1 to NaNNumber(array) is like Number(array.toString()).

var empty = [];
var one = [1];
var nonempty = [1,2,3];

msg('Number(empty) == ' + Number(empty));
msg('Number(one) == ' + Number(one));
msg('Number(nonempty) == ' + Number(nonempty));

MSIE converts all strings representing negative hexadecimal numbers to NaN.

msg('Number("0x10") == ' + Number("0x10"));
msg('Number("-0x10") == ' + Number("-0x10"));
          
Execution Contexts

Before any JavaScript code is executed, a unique Global object is created which has {DontEnum} properties for the standard built-in objects (Math, String, Date, etc.) and any properties created by the host environment.

The environment in which a JavaScript program is executing is maintained in a stack of objects called execution contexts. A stack, also known as a Last in First Out (LIFO) list is a list of data items where items are added (pushed) or removed (popped) from one end called the top of the stack. The execution context at the top of the stack is used by the executing program as the current context.

Each execution context maintains an internal object called the variable object which is used to hold references to the variables and functions created in that context. Each variable (or function) is stored in the variable object as a property with property name equal to the variable (or function) name.

Each execution context also maintains a scope chain which is a list of objects which are searched when a variable or name needs to be resolved. Whenever JavaScript needs to resolve a reference to a name, it first looks in the current object in the scope chain for a property with the same name. If it is found, the data referenced by that propery is returned as the value of the name. If the name is not found, the next object in the scope chain is searched and so on until either the name has been resolved or all objects in the scope chain have been searched. Once created for a context, the scope chain is only effected by with statements and catch clauses.

Example Scope_Chain
var v = 'global scope';
var o = {v: 'object scope'};
var e;

msg('global this  == ' + this);
msg('global v     == ' + v);
msg('global e     == ' + e);

function test()
{
  msg('function this == ' + this);
  msg('function v    == ' + v);
  
  var v = 'function scope';

  with (o)
  {
    msg('with this == ' + this);
    msg('with o v  == ' + v);
  }

  try
  {
    throw 'string exception';
  }
  catch(e)
  {
    msg('catch this == ' + this);
    msg('catch e    == ' +  
         e.name + ': ' + e.message);
    e = 'catch scope';
  }
  msg('function e == ' + e);
  msg('function v == ' + v);
}
test();

msg('global v == ' + v);
msg('global e == ' + e);
        

MSIE creates the catch variable e containing the thrown exception in function scope. This means the variable e exists after the catch clause has finished executing but ceases to exist after the function where the catch clause was located exits. This is not the same as Mozilla which does not define the catch variable outside of the catch clause.

Both MSIE and Mozilla bind the initial scope to a function when it is created as a function expression. In the following example, function f1() is bound to a scope consisting of the global object while function f2() is defined inside a with clause which adds the object o to the beginning of the scope followed by the global object.

var v = 'value 1';
var o = {v: 'value 2'};

var f1 = function () { msg('v == ' + v); };

with (o)
{
  var f2 = function () { msg('v == ' + v); };
}

// call with the initial values 
f1();
f2();

// now modify the values 
v = 'modified value 1';
o.v = 'modified value 2';
f1();
f2();

However when the function is defined using a function declaration, MSIE differs from Mozilla and binds the function to the global scope regardless of any scope changes introduced by with clauses.

var v = 'value 1';
var o = {v: 'value 2'};

function f1() { msg('v == ' + v); };

with (o)
{
  function f2() { msg('v == ' + v); };
}

// call with the initial values 
f1();
f2();

// now modify the values 
v = 'modified value 1';
o.v = 'modified value 2';
f1();
f2();

Each execution context maintains a special value called the this value which is determined by how the context was created and the type of code being executed. The this value can not be changed to point to a different object, although properties can be added or removed from it.

Global Execution Context

Whenever a JavaScript program begins, a Global execution context is created and pushed onto the top of the stack. The scope chain is initialized to contain just the global object and the this value is set to point to the global object. Variables are created as {DontDelete} properties of the global object.

Example Global_Execution_Context
var globalVar = 'this is a global variable';

msg('globalVar = ' + globalVar);
msg('this.globalVar = ' + globalVar);

try
{
  // it should not be possible delete the variable
  // but no error should be thrown.
  delete this.globalVar;
  msg('this.globalVar after delete = ' + this.globalVar);
}
catch(e)
{
  msg('An unexpected error occured deleting a globalVar variable ' +  
      e.name + ': ' + e.message);
}

Mozilla (JavaScript1.1, JavaScript1.2) will throw an error when deleting a global variable since it is defined as {DontDelete}. Note that Mozilla JavaScript1.3 and later do not have the behavior and that Mozilla JavaScript1.1, JavaScript1.2 do not throw errors when deleting function local variables even though they are also {DontDelete}.

Eval Code Context

Whenever JavaScript code is compiled using the eval function, an eval execution context is created and pushed onto the stack until the eval'd code completes when the eval execution context is removed from the stack.

The calling execution context determines the scope chain, the variable object and the this value for the eval execution context. If there is no calling context, the scope chain, variable object and the this value are determined in the same way as for the global execution context.

Example Eval_Execution_Context
eval("var evalVar = 'this is an eval variable'");
msg('evalVar = ' + evalVar);
msg('this.evalVar = ' + evalVar);
try
{
  // it should be possible delete the variable
  // and no error should be thrown.
  delete this.evalVar;
  msg('this.evalVar after delete = ' + this.evalVar);
}
catch(e)
{
  msg('An unexpected error occured deleting a global variable ' +  
      e.name + ': ' + e.message);
}
Function Execution Context

Each time a function call is performed, a function execution context is created and pushed onto the top of the stack and then removed from the stack when the function call ends.

An Activation Object is created in the execution context for each function call and is treated as the variable object for the execution context. The scope chain for the context is created by placing the activation object in front of the scope chain of the calling execution context.

An arguments object is added as a {DontEnum} property to the variable. The arguments object is initialized with the following properties:

callee

a {DontEnum} property which points to the function object being executed.

caller (non-standard)

In Mozilla and MSIE, the non-standard caller property was used to point to the function which called the currently executing function. This property has been removed from recent releases of both browsers due to security considerations.

function Caller()
{
  msg('Caller: Caller.arguments ' + Caller.arguments);
  Callee();
}
function Callee()
{
  msg('Callee: arguments.caller ' + arguments.caller);
}
Caller();
length

a {DontEnum} property which contains the number of actual arguments in the function call.

a property for each argument

For each argument supplied, a {DontEnum} property of the same name is created in the arguments.

Mozilla JavaScript1.1, JavaScript1.2 will allow function arguments to be enumerated as zero based indexes into the arguments list. This is not possible in Mozilla JavaScript1.3 or later.

In normal function calls, the this value remains unchanged from that of the calling context however in the context of a constructor call (new SomeFunction()), the this value is set to the newly created JavaScript object.

An example of a normal function call…

Example Function_Call_Context
var global = this;
var avar   = 'this is a global variable';

func('this is arg0', 'this is arg1');

msg('After func this === global is ' + (this === global));
msg('After func avar should be unchanged ' + avar);

function func(arg0, arg1, arg2)
{
  // the this value should point to the global object
  msg('Inside func this === global is ' + (this === global));

  // declare a varible local to the function
  var avar = 'this is a local variable';
  msg('Inside func avar == ' + avar);

  // attempt to delete the local variable
  try
  {
    msg('delete avar  == ' + (delete avar));
  }
  catch(e)
  {
    msg('an error occured during delete avar ' +  
      e.name + ': ' + e.message);
  }
  msg('typeof avar == ' + typeof avar);

  // the length of the function should be the number
  // of defined arguments. In this case 3.
  msg('func.length is ' + func.length);
  msg('arguments ' + arguments);

  // the length of the arguments object should be the
  // number of actual arguments the function was called with.
  // In this example it should be 2.
  msg('arguments.length is ' + arguments.length);

  // this function
  msg('arguments.callee <pre>' + arguments.callee +
      '</pre>');

  // the caller function which will be undefined.
  msg('arguments.caller <pre>' + arguments.caller + '</pre>');

  // the properties of the arguments object should be {DontEnum} 
  // so this should output the empty string.
  var arglist = '';
  for (var arg in arguments)
  {
    arglist += arg + ', ';
  }
  msg('Enumerable properties of arguments ' + arglist);
}

An example of a constructor function call…

Example Constructor_Call_Context
var global = this;
var avar   = 'this is a global variable';
var instance = new func('this is arg0', 'this is arg1');

msg('After func this === global is ' + (this === global));
msg('this.propname should be undefined ' + this.propname);
msg('instance.propname should be defined ' + instance.propname);

function func(arg0, arg1, arg2)
{
  // the this value should point to the newly created object
  // and _not_ the global object.
  msg('Inside func this === global is ' + (this === global));

  // add a property to this instance
  this.propname = 'a property in our new object';

  // attempt to delete the local variable
  try
  {
    msg('delete avar  == ' + (delete avar));
  }
  catch(e)
  {
    msg('an error occured during delete avar ' +  
      e.name + ': ' + e.message);
  }
  msg('typeof avar == ' + typeof avar);

  // the length of the function should be the number
  // of defined arguments. In this case 3.
  msg('func.length is ' + func.length);
  msg('arguments ' + arguments);

  // the length of the arguments object should be the
  // number of actual arguments the function was called with.
  // In this example it should be 2.
  msg('arguments.length is ' + arguments.length);

  // this function
  msg('arguments.callee <pre>' + arguments.callee +
      '</pre>');

  // the caller function which will be undefined.
  msg('arguments.caller <pre>' + arguments.caller + '</pre>');

  // the properties of the arguments object should be {DontEnum} 
  // so this should output the empty string.
  var arglist = '';
  for (var arg in arguments)
  {
    arglist += arg + ', ';
  }
  msg('Enumerable properties of arguments ' + arglist);
}
JavaScript Expressions
Identifiers

An identifier is a sequence of characters beginning with either $ (dollar sign), _ (underscore) or a unicode letter followed by unicode letters, unicode digits, underscores (_) or dollar signs ($). The characters can also be written using unicode escape sequences. Note that identifiers are not restricted to the normal latin character set, but are instead allowed to have letters and digits from the unicode character set.

// Valid Identifiers

// latin type variable identifiers
var _foo123;
var $foo123;
var foo123;
var foo_123$

// hindi variable identifier using unicode escapes
var \u092F\u0942\u0928\u093F\u0915\u094B\u0921 = 'unicode';
msg('\u092F\u0942\u0928\u093F\u0915\u094B\u0921 == ' + 
    \u092F\u0942\u0928\u093F\u0915\u094B\u0921);

// hindi variable identifier using unicode characters
var यूनिकोड = 'unicode';
msg('यूनिकोड == ' + यूनिकोड);

msg('Test passed');
// Invalid Identifiers
// Mozilla will fire a window.onerror or exception handler 
// for compile time errors, however MSIE will not. 
try
{
  eval('var 0foo;');

  // the next statement is an error
  // the next statement should not be executed
  msg('Test failed: invalid identifier 0foo == ' + 0foo);
}
catch(e)
{
  msg('Test passed: 0foo is an invalid identifier ' +  
      e.name + ': ' + e.message);
}
Reserved Words

Keywords are identifiers which have special meanings in JavaScript and should not be used as variable or property names. Reserved words are identifiers which may be used as keywords in future versions of JavaScript and should not be used as variable or property names.

Example 7.5.1 - Reserved Words

// test if a word can be declared as var
function testvar(words)
{
  var e;
  for (var i = 0; i < words.length; i++)
  {
    var word = words[i];
    try
    {
      eval('var ' + word + ';');
      msg('test failed: ' + word + ' is declarable');
    }
    catch(e)
    {
      msg('test passed: ' + word + ' is not declarable ' +  
      e.name + ': ' + e.message);
    }
  }
}

// test if a word can be assigned to
function testwrite(words)
{
  var e;
  for (var i = 0; i < words.length; i++)
  {
    var word = words[i];
    try
    {
      eval(word + ' = "foo";');
      msg('test failed: ' + word + ' is writable');
    }
    catch(e)
    {
      msg('test passed: ' + word + ' is not writable ' +  
      e.name + ': ' + e.message);
    }
  }
}

// keywords
var keywords = 
['break',        'else',      'new',      'var',        'case', 
'finally',      'return',    'void',     'catch',      'for', 
'switch',       'while',     'continue', 'function',   'this', 
'with',         'default',   'if',       'throw',      'delete', 
'in',           'try',       'do',       'instanceof', 'typeof'];

// future reserved words
var reserved = 
['abstract',     'enum',      'int',      'short',      'boolean', 
'export',       'interface', 'static',   'byte',       'extends', 
'long',         'super',     'char',     'final',      'native', 
'synchronized', 'class',     'float',    'package',    'throws', 
'const',        'goto',      'private',  'transient',  'debugger', 
'implements',   'protected', 'volatile', 'double',     'import', 
'public'];

testvar(keywords);
testvar(reserved);
testwrite(keywords);
testwrite(reserved);

MSIE incorrectly allows the following to be declared as variables and assigned values: abstract, int, short, boolean, interface, static, byte, long, char, final, native, synchronized, float, package, throws, goto, private, transient, implements, protected, volatile, double, public.

In Mozilla 1.7 (Firefox 1.0) JavaScript 1.1, JavaScript 1.2 instanceof, enum, export, debugger are declarable and writable however in Mozilla 1.7 (Firefox 1.0) for JavaScript 1.3 and later the other keywords and reserved words are not declarable or writable.

Mozilla 1.8 (Firefox 1.1) and later (Bugzilla 240317) relax the declaration and assignment of reserved identifiers to improve MSIE compatibility. The following words will no longer throw errors but will still issue JavaScript warnings: abstract, enum, int, short, boolean, interface, static, byte, extends, long, super, char, final, native, synchronized, class, float, package, throws, goto, private, transient, implements, protected, volatile, double, public

Function Expressions

Mozilla can define functions in conditionals. If the code branch is not executed due to the conditional the function is not defined. MSIE however uses the definition of the last occurence of the function. Both Mozilla and MSIE can conditionally define function expressions.

// works in Mozilla, not MSIE
if (true)
{
  function f() { return 'true'; };
}
else
{
  function f() { return false; };
}
msg('Conditional Function: ' + f()); 
// works in Mozilla and MSIE
var f;
if (true)
{
  f = function () { return 'true'; };
}
else
{
  f = function () { return false; };
}
msg('Conditional Function: ' + f()); 

MSIE violates the ECMSAcript standard since it can reference a function name outside of the function expression.

f = function foo(){alert('foo');};
foo();
Operators
Operator Precedence and Associativity
Description Operator Associativity
member of []   . left to right
(grouping | function call), create instance ()   new right to left
unary !   ~   ++   --   +   -   typeof   void   delete right to left
multiplicative *   /   % left to right
addition +  - left to right
bitwise shift <<   >>   >>> left to right
relational <   <=   >   >=   in  instanceof left to right
equality ==  ===   !=   !== left to right
bitwise and & left to right
bitwise xor ^ left to right
bitwise or | left to right
logical and && left to right
logical or || left to right
conditional ?: right to left
assignment =   *=   /=   %=   -=   <<=   >>=   >>>=   &=   ^=   |= right to left
comma , left to right
Member of Operators

Mozilla has the ability to define getter and setter methods for user defined objects. Note that Mozilla introduced this feature in JavaScript 1.5, however it is available for all language versions in Mozilla.

  • deprecated - can only create getters and setters as local properties.

    {_prop: stuff, get prop() {...}, set prop() {...}}
    
    or
    instance.propname getter = function(arglist) {...};
    
    or
    instance.propname setter = function(arglist) {...};
    
  • recommended - can create getters and setters as shared properties.

    someObject.prototype.__defineGetter__('propname', 
                                          function(arglist) )
    someObject.prototype.__lookupGetter__('propname');
    
    and
    someObject.prototype.__defineSetter__('propname', 
                                          function(arglist) )
    someObject.prototype.__lookupSetter__('propname');
    
var deprecated_1 = {
  _prop: 'default value',

  get prop()  { return this._prop; },
  set prop(v) { return this._prop = v; }
}

msg('deprecated_1.prop == ' + deprecated_1.prop);
     deprecated_1.prop = 'foo';
msg('deprecated_1.prop == ' + deprecated_1.prop);

var deprecated_2 = {
  _prop: 'default value'
};

deprecated_2.prop getter = 
function()  { return this._prop; };

deprecated_2.prop setter = 
function(v) { return this._prop = v; };


msg('deprecated_2.prop == ' + deprecated_2.prop);
     deprecated_2.prop = 'foo';
msg('deprecated_2.prop == ' + deprecated_2.prop);

function NonDeprecated(v)
{
  this.prop = v;
}

NonDeprecated.prototype.__defineGetter__('prop', 
  function() { 
    return this._prop;
  }
);

NonDeprecated.prototype.__defineSetter__('prop', 
  function (v) { 
    return this._prop = v; 
  }
);
 
var nondeprecated = new NonDeprecated('initial value');

// call getter
msg('nondeprecated.prop == ' + nondeprecated.prop);

// call setter
nondeprecated.prop = 'foo';

msg('nondeprecated.prop == ' + nondeprecated.prop);

// lookup getter
msg('nondeprecated.__lookupGetter__(\'prop\') == ' + 
     nondeprecated.__lookupGetter__('prop'));


// lookup setter
msg('nondeprecated.__lookupSetter__(\'prop\') == ' + 
     nondeprecated.__lookupSetter__('prop'));

The __noSuchMethod__ handler was introduced in Mozilla 1.6 in Bug 196097 '__noSuchMethod__' handler for trapping calls to undefined object methods.

// define on an object instance
var obj = {};

obj.__noSuchMethod__ = 
function(id, args) {
  msg('Undefined method ' + id + 
      ' called with arguments (' + args.join(', ') + ')');
};

obj.foo('bar');

// define on an object prototype
Object.prototype.__noSuchMethod__ = 
function(id, args) {
  msg('Undefined method ' + id + 
      ' called with arguments (' + args.join(', ') + ')');
};

var date = new Date();

date.baz('foobar');
	    
Member of ([]) Operator

Syntax

expression[propertyexpression]
Access Object Properties

Returns the value of a property from an instance of an object.

The result of evaluating expression must be or be convertable to an instance of an object, otherwise a TypeError is thrown. For example, it is a TypeError to attempt to access or set a property on undefined or null values.

try
{
  null['prop'] = 'foo';
}
catch(e)
{
  msg(e.name + ': ' + e.message)
}

The name of the property is obtained by evaluating propertyexpression and converting the result to a string primitive value. There is no restriction on the characters which can be used as part of the property name.

var object = {};
object['0' + Math.PI] = 'bar';

If the property exists in the object, the values is returned, otherwise undefined is returned.

var object = {foo: 'bar'};
msg('object["foo"] == ' + object["foo"]);
msg('object["fu"]  == ' + object["fu"]);
Access Array items

Instances of Array Objects treat the numeric index (position) values of items in the array as special object property values which must be less than 232. If an item does not exist at the specified position in the array, undefined is returned.

Neither Mozilla nor MSIE appear to limit the index values to less than 232.
var array = [0, 1, 2];
msg('array[0] == ' + array[0]);
msg('array[1] == ' + array[1]);
msg('array[2] == ' + array[2]);
msg('array[3] == ' + array[3]);

var exponents = [32, 64, 128, 256];
for (var i = 0; i < exponents.length; i++)
{
  var exponent = exponents[i];
  var index = Math.pow(2,exponent);
  try
  {
    array[index] = index;
    msg('array[' + index + '] == ' + array[index]);
  }
  catch(e)
  {
    msg('Exception attempting to set array item at index ' + 
        index + ' ' + 
      e.name + ': ' + e.message);
  }
}
Access characters in Strings
Mozilla extends the [] operator to allow it to access characters from string values as if the string were an array of characters. This is not supported in MSIE.
var string = "abc";
msg('string[0] == ' + string[0]);
msg('string[1] == ' + string[1]);
msg('string[2] == ' + string[2]);
msg('string[3] == ' + string[3]);
Member of (.) Operator

.

Grouping (()) Operator

grouping and function call

Create instance (new) Operator
// new Operand, Operand must be an Object with Constructor else 
// throws TypeError
try
{
  var o  = new 'foo';
}
catch(e)
{
  msg('Test passed : ' +  
      e.name + ': ' + e.message);
  if (e instanceof TypeError)
  {
    msg('Error Object is a TypeError');
  }
  else
  {
    msg('Error: Error Object is not a TypeError');
  }
}
Unary Operators

.

>Unary Logical Not (!) Operator

Unary Logical Not (!) converts the value to boolean, then returns false if the value was true and true otherwise.

Unary Bitwise Complement (~) Operator

Unary Bitwise Complement ~ converts its operand to a 32-bit integer, then performs bitwise complement (switching 0 ↔ 1). Non-numeric values are converted to -1 (the complement of 0).

Example Unary_Bit_Negation
msg('~(+1) == ' + ~(+1))
msg('~(-1) == ' + ~(-1));
msg('~0x0f) == ' + ~0x0f);
msg('~(NaN) == ' + ~(NaN));
msg('~(0)  == ' + ~(0));
msg('~(\'1\') == ' + ~('1'));
msg('~(\'a\') == ' + ~('a'));
Increment (++) Operator

The increment operator (++) is used to add the number 1 to a variable or object property. It can be applied either in prefix (++variable) or postfix (variable++) forms. When used as a prefix, ++variable, it first converts the value to a primitive number value, increments the value and then returns the new value as a primitive number value for use in the expression. When used as a postfix, variable++, it increments the value but returns the original value for use in the expression.

++ can only be used on named instances containing values which can be converted to number primitive values.

Example Increment_Operator
var value = 0;
msg('before: value == ' + value + 
    ', during: ++value == ' + ++value + 
    ', after: value == ' + value);

value = 0;
msg('before: value == ' + value + 
    ', during: value++ == ' + value++ + 
    ', after: value == ' + value);

// instances of Number Objects are converted to primitive number values
value = new Number(0);
msg('before: typeof value == ' + typeof value + 
    ', value == ' + value + 
    ', during: value++ == ' + value++ + 
    ', after: typeof value == ' + typeof value + 
    ', value == ' + value);

// instances of strings are converted to primitive number values
value = '0';
msg('before: typeof value == ' + typeof value + 
    ', value == ' + value + 
    ', during: value++ == ' + value++ + 
    ', after: typeof value == ' + typeof value + 
    ', value == ' + value);
Example Increment_Operator_Errors
try
{
  // attempt to increment a literal is a compile time error
  // use eval to force runtime error.
  eval('++1;');
  msg('Test failed. ++1 == ' + eval('++1'));
}
catch (e)
{
  msg('The operand of ++ can not be a literal');
}
try
{
  // It is an error to increment a string if it can 
  // not be converted to a primitive number value.
  var s = 'string';
  eval('++s;');
  msg('Test failed. ++s == ' + string);
}
catch (e)
{
  msg('The operand of ++ must convertable to a number');
}
Decrement (--) Operator

The increment operator (--) is used to subtract the number 1 from a variable or object property. It can be applied in prefix (--variable) or postfix (variable--) forms. When used as a prefix, --variable, it first converts the value to a primitive number value, increments the variable and then returns the new value as a primitive number value for use in the expression. When used as a postfix, variable--, it increments the value but returns the original value for use in the expression.

-- can only be used on named instances containing values which can be converted to number primitive values.

Unary (+) Operator

unary + operator converts its single operand to a primitive number value. If the operand can not be converted to a number, the value NaN is returned.

var before = '1';
var after  = +before;
msg('typeof before == ' + typeof before + ', before == ' + before);
msg('typeof after == ' + typeof after + ', after == ' + after);

before = 'a';
after = +before;
msg('typeof before == ' + typeof before + ', before == ' + before);
msg('typeof after == ' + typeof after + ', after == ' + after);
Unary (-) Operator

unary - operator converts its single operand to a primitive number value and then returns the negative of that value. If the operand can not be converted to a number, the value NaN is returned.

var before = '1';
var after  = -before;
msg('typeof before == ' + typeof before + ', before == ' + before);
msg('typeof after == ' + typeof after + ', after == ' + after);

before = 'a';
after = -before;
msg('typeof before == ' + typeof before + ', before == ' + before);
msg('typeof after == ' + typeof after + ', after == ' + after);
Typeof (typeof) Operator

The typeof operator returns a string value representing the primitive type of its operand.

typeof operator results
Input Type Output
undefined 'undefined'
null 'object'
primitive boolean 'boolean'
primitive number 'number'
primitive string 'string'
any native object 'object'
any native function 'function
host object implementation-dependent
Example typeof Operator
msg('typeof undefined   == ' + typeof undefined);
msg('typeof null        == ' + typeof null);
msg('typeof true        == ' + typeof true);
msg('typeof 1           == ' + typeof 1);
msg('typeof \'s\'        == ' + typeof 's');
msg('typeof new Boolean == ' + typeof new Boolean);
msg('typeof new Number  == ' + typeof new Number);
msg('typeof new String  == ' + typeof new String);
msg('typeof new Object  == ' + typeof new Object);
msg('typeof function f(){} == ' + typeof function f(){});
Void (void) Operator

The void operator evaluates an expression but discards any return value and returns undefined.

Example void Operator
msg('void (1+2) == ' + void (1+2));
Delete property (delete) Operator

The delete operator removes a property from an Object and returns true if the variable does not exist after being removed. Note that delete has no effect on JavaScript object properties which are defined to be {DontDelete}.

Example Delete Operator
// attempt to delete a declared variable
// which should fail without an error
var value  = 'a value';
var before = value;
var result = delete value;
var after  = value;
msg('before: value == ' + before +
    ' result: ' + result + 
    ' after: value == ' + after);

// attempt to delete an undeclared variable
// which should succeed
undeclared  = 'a value';
var before = undeclared;
var result = delete undeclared;
var after  = typeof(undeclared);
msg('before: undeclared == ' + before +
    ' result: ' + result + 
    ' after: undeclared == ' + after);

// attempt to delete a property from a user defined object
var object = {property: 'value'}
var before = object.property;
var result = delete object.property;
var after  = object.property;
msg('before: object.property == ' + before +
    ' result: ' + result + 
    ' after: object.property == ' + after);

// attempt to delete a property that does not exist
before = object.foo;
result = delete object.foo;
after  = object.foo;
msg('before: object.foo == ' + before +
    ' result: ' + result + 
    ' after: object.foo == ' + after);

// attempt to delete a {DontDelete} property 
before = Math.PI;
result = delete Math.PI;
after  = Math.PI;
msg('before: Math.PI == ' + before +
    ' result: ' + result + 
    ' after: Math.PI == ' + after);
Multiplication (*) Operator

Multiplication * operator converts its operands to number values, then returns the product of the two values as the result. If the conversion results in NaN, the result is NaN.

Example Multiplication_Operator
msg('2 * 2 == ' + (2*2));
msg('"2" * "2" == ' + ("2" * "2"));
msg('"a" * "b" == ' + ("a" * "b"));
Division (/) Operator

Division / operator converts its operands to number values, then returns the quotient of the two values as a result. If the divisor is 0, Infinity is returned. If the conversion results in NaN, the result in NaN.

Example Division_Operator
msg('1 / 2 == ' + (1 / 2));
msg('1 / 0 == ' + (1 / 0));
msg('"1" / "2" == ' + ("1" / "2"));
msg('"a" / "b" == ' + ("a" / "b"));
Modulus (%) Operator

The Modulus % operator converts it operands to number values, then returns the remainder of a division of its left operand by its right. Unlike C, % can operate on non-integers.

  • If the conversion of either operand results in NaN, the result in NaN.
  • If the left operand is Infinity, or the right operand is 0, the result is NaN.
  • If the left operand is 0 and the right operand is not Infinite, the result is 0.
  • otherwise the sign of the result equals the sign of the left operand and the result is left*right*q for the largest integer q which has the same sign of left/right such that q <= left/right.
Example Modulus Operator
msg('"a" % 2 == ' + "a" % 2);
msg('2 % "a" == ' + 2 % "a");
msg('Infinity % 2 == ' + Infinity % 2);
msg('0 % Infinity == ' + 0 % Infinity);
msg('1 % Infinity == ' + 1 % Infinity);
msg('3 % 0 == ' + 3 % 0);
msg('3 % 2 == ' + 3 % 2);
msg('(-3) % 2 == ' + (-3) % 2);
msg('3 % (-2) == ' + 3 % (-2));
msg('3.5 % 2.5 == ' + 3.5 % 2.5);
msg('Math.PI % 3 == ' + Math.PI % 3);
Addition (+) Operator

Depending on the types of its operands, + either performs numeric addition or string concatenation.

If either operand is a string (or convertable to a string), the + operator performs string concatenation.

If both operands are numbers (or convertable to numbers), the + operator performs numeric addition.

Example Addition Operator
// string concatenation
msg('"1" + "2" == ' + ("1" + "2"));
msg('"1" + 2 == ' + ("1" + 2));
msg('1 + "2" == ' + (1 + "2"));
msg('"a" + "2" == ' + ("a" + "2"));
msg('"a" + 2 == ' + ("a" + 2));
msg('1 + "a" == ' + (1 + "a"));

// numeric addition
// note how the grouping operator () forces the intermediate result
// of (1 + 2) to be calculated as a numeric addition 
msg('1 + 2 == ' + (1 + 2));

// without the grouping operator string concatenation would have 
// been performed
msg('1 + 2 == ' + 1 + 2);
Subtraction (-) Operator

The subtraction - operator converts its operands to number values, then returns the result of subtracting the right operand from the left.

// subtract a number from a number
msg('2 - 1 == ' + (2 - 1));

// note how the grouping operator forces the intermediate result
// of ("2" - "1") to be calculated as numeric subtraction.
msg('"2" - "1" == ' + ("2" - "1"));

// without the grouping operator, the expression attempts 
// to subtract a string value from a string, resulting in NaN
msg('"2" - "1" == ' + "2" - "1");
Bit Operators

.

Left Shift (<<) Operator

Left Shift << converts its operands to 32 bit integer values, then shifts the bits in the left operand to the left by the number of bits specified in the right operand and filling the new positions with 0.

Example Left Shift Operator
msg('(1 << 1) == ' + (1 << 1));
msg('(-1 << 1) == ' + (-1 << 1));
msg('(2.6 << 2) == ' + (2.6 << 2));
msg('(Math.PI << 3) == ' + (Math.PI << 3));
msg('(NaN << 1) == ' + (NaN << 1));
msg('(Infinity << 1) == ' + (Infinity << 1));
msg('("a" << 1) == ' + ("a" << 1));
Signed Right Shift (>>) Operator

Signed Right Shift >> converts its operands to 32 bit integer values, then shifts the bits in the left operand to the right by the number of bits specified in the right operand and filling the new positions with the bit in the left most position.

Example Signed Right Shift Operator
msg('(1 >> 1) == ' + (1 >> 1));
msg('(-1 >> 1) == ' + (-1 >> 1));
msg('(2.6 >> 2) == ' + (2.6 >> 2));
msg('(Math.PI >> 3) == ' + (Math.PI >> 3));
msg('(NaN >> 1) == ' + (NaN >> 1));
msg('(Infinity >> 1) == ' + (Infinity >> 1));
msg('("a" >> 1) == ' + ("a" >> 1));
Unsigned Right Shift (>>>) Operator

UnSigned Right Shift >>> converts its operands to 32 bit integer values, then shifts the bits in the left operand to the right by the number of bits specified in the right operand and filling the new positions with 0.

Example Unsigned Right Shift Operator
msg('(1 >>> 1) == ' + (1 >>> 1));
msg('(-1 >>> 1) == ' + (-1 >>> 1));
msg('(2.6 >>> 2) == ' + (2.6 >>> 2));
msg('(Math.PI >>> 3) == ' + (Math.PI >>> 3));
msg('(NaN >>> 1) == ' + (NaN >>> 1));
msg('(Infinity >>> 1) == ' + (Infinity >>> 1));
msg('("a" >>> 1) == ' + ("a" >>> 1));
Relational and Logical Operators

.

Less than (<) Operator

Performs either a numeric or string comparison returning true if the left operand is less than the right operand, false if the left operand is greater than or equal to the right operand, or undefined if either of the operands is NaN. If both of the operands are strings, then a string comparison is performed, otherwise a numeric comparison is performed. If during the numeric comparison, one of the operands evaluates to NaN, then undefined is returned which is equivalent to false.

Example Less Than Operator
msg('1 < 2 == ' + (1 < 2));
msg('NaN < 1 == ' + (NaN < 1));
msg('1 < Infinity == ' + (1 < Infinity));
msg('10 < 2 == ' + (10 < 2));
msg('"10" < "2" == ' + ("10" < "2"));
msg('"10" < 2 == ' + ("10" < 2));
msg('1 < "a" == ' + (1 < "a"));
msg('"a" < "b" == ' + ("a" < "b"));
Greater than (>) Operator

Performs either a numeric or string comparison returning true if the left operand is greater than the right operand and false otherwise. If both of the operands are strings, then a string comparison is performed, otherwise a numeric comparison is performed.

Less than or equal (<=) Operator

Performs either a numeric or string comparison returning true if the left operand is less than or equal to the right operand and false otherwise. If at least one of the operands is a string, then a string comparison is performed, otherwise a numeric comparison is performed.

Greater than or equal (>=) Operator

Performs either a numeric or string comparison returning true if the left operand is greater than or equal to the right operand and false otherwise. If at least one of the operands is a string, then a string comparison is performed, otherwise a numeric comparison is performed.

Instanceof (instanceof) Operator

Tests if the left operand is an object instance which has the right operand as an ancestor object. In other words, tests if the left operand is an object instance which has the prototype of the right operand in its prototype chain.

Example instanceof Operator
// all JavaScript Native Objects are instances of Object
var date = new Date();

msg('date instanceof Object == ' + (date instanceof Object));

// throw a TypeError if the right operand is not an object
try
{
  msg('date instanceof "foo" == ' + (date instanceof "foo"));
  msg('Test failed. Should have thrown TypeError');
}
catch(e)
{
  msg('Right operand of instanceof must be an object ' +  
      e.name + ': ' + e.message);
}

instanceof is not supported in Mozilla JavaScript1.1, JavaScript1.2 but is supported in Mozilla JavaScript1.3 and later.

Not sure how to test ECMAScript 11.8.6 The instanceof operator step 6.

In (in) Operator

Tests if the left operand (after conversion to a primitive string value) is the name of a property in the object named in the right operand. The property can be a shared property which exists only in the right operands prototype chain. Throws a TypeError if the right operand is not an object.

Example in Operator
// test local properties
var object = { propname: "value" };

// test using primitive string name
msg('"propname" in object == ' + ("propname" in object));

// test using String object
msg('(new String("propname")) in object == ' + 
    ((new String("propname")) in object));

// test TypeError
try
{
  msg('"propname" in "foo" == ' + ("propname" in "foo"));
  msg('Test Failed.');
}
catch(e)
{
  msg('Test Passed. Right operand of in must be an object. ' +  
      e.name + ': ' + e.message);
}
Equals (==) Operator

Returns true if its two operands are equal as defined below.

The following discussion uses x == y as the example equality test expression.

  • x != y is equivalent to !(x == y)
  • x == y is equivalent to y == x (neglecting side effects of evaluation)
  • "" + x == "" + y forces string comparison
  • x - 0 == y - 0 forces numeric comparison
  • !x == !y forces boolean comparison
undefined == undefined
return true
msg('undefined == undefined ' + (undefined == undefined));
null == null
return true
msg('null == null ' + (null == null));
null == undefined or undefined == null
return true
msg('null == undefined ' + (null == undefined));
msg('undefined == null ' + (undefined == null));
typeof x, typeof y are both "string"
return true if x and y consist of the exact same sequence of characters otherwise return false.
msg('"abc" == "abc" ' + ("abc" == "abc"));
msg('"abc" == "abcd" ' + ("abc" == "abcd"));
msg('"abc == "ABC" ' + ("abc" == "ABC"));
typeof x, typeof y both are "number"
  • if x or y is NaN, return false
  • if x is +0 and y is -0 (or vice-versa), return true
  • if x and y is the same number, then return true otherwise return false

To determine if a number n is NaN, use the function isNaN(n).

msg('NaN == NaN ' + (NaN == NaN));
msg('NaN == 1 ' + (NaN == 1));
msg('1 == NaN ' + (1 == NaN));
msg('isNaN(NaN) ' + isNaN(NaN));
msg('+0 == -0 ' + (+0 == -0));
msg('-0 == +0 '  + (-0 == +0));
msg('12e5 == 12e5 ' + (12e5 == 12e5));
msg('1 == 2 ' + (1 == 2));
typeof x, typeof y are both "boolean"
return true if x and y are either both true or both false otherwise return false.
msg('true == true ' + (true == true));
msg('false == false ' + (false == false));
msg('true == false ' + (true == false));
msg('false == true ' + (false == true));
typeof x, typeof y are both "object"
return true if x and y refer to the same object. Note that different objects with the same value do not compare as equal thus == is not a transitive operator and == does not form an equivalence relation.
var o1 = new Object();
var o2 = o1;
var o3 = new Object();
msg('o1 == o2 ' + (o1 == o2));
msg('o1 == o3 ' + (o1 == o3));
var s1 = "abc";
var s2 = new String("abc");
var s3 = new String("abc");
msg('s1 == s2 ' + (s1 == s2));
msg('s1 == s3 ' + (s1 == s3));
msg('s2 == s3 ' + (s2 == s3));
vice-versa" typeof x is "number" and typeof y is "string" or vice-versa
convert the "string" value to a primitive number value and return the result of comparing the two numbers.
msg('"1" == 1 ' + ("1" == 1));
msg('2 == "2" ' + (2 == "2"));
typeof x is "boolean" and typeof y is not "boolean" or vice versa
convert the "boolean" value to a primitive number value and compare the result.
msg('true == 1 ' + (true == 1));
msg('false == 0 ' + (false == 0));
msg('true == NaN ' + (true == NaN));
msg('false == NaN ' + (false == NaN));
msg('true == 10 ' + (true == 10));
msg('false == 10 ' + (false == 10));

msg('true == "1" ' + (true == "1"));
msg('false == "0" ' + (false == "0"));
msg('true == "10" ' + (true == "10"));
msg('false == "10" ' + (false == "10"));

msg('true == null ' + (true == null));
msg('false == null ' + (false == null));
msg('true == undefined ' + (true == undefined));
msg('false == undefined ' + (false == undefined));
msg('true == new Object() ' + (true == new Object()));
msg('false == new Object() ' + (false == new Object()));
typeof x is either "string" or "number" and typeof y is "object" or vice-versa
convert the "object" value to a primitive value and compare the result.
var s1 = "abc";
var s2 = new String("abc");
var n1 = 123;
var n2 = new Number(123);
msg('s1 == n2 ' + (s1 == n2));
msg('n1 == s2 ' + (n1 == s2));

Mozilla JavaScript 1.2 only behaves as if strict equality === specified

var result = (1 == "1");
msg ('Test ' + (result?'Passed':'Failed') + 
     ': (1 == "1") == ' + result);
Does not equal (!=) Operator

return false if left == right is true otherwise return true

Mozilla JavaScript 1.2 only behaves as if strict in-equality !== specified

var result = (null != undefined);
msg ('Test ' + (result?'Failed':'Passed') + 
     ': (null != undefined) == ' + result);
Strict Equals (===) Operator

Performs a strict equality comparison on it operands as defined below.

The following discussion uses x === y as the example equality test expression.

if typeof x differs from typeof y
return false
undefined === undefined
return true
msg('undefined === undefined ' + (undefined === undefined));
null === null
return true
msg('null === null ' + (null === null));
typeof x, typeof y are "number"
  • if x or y is NaN, return false
  • if x is +0 and y is -0 (or vice-versa), return true
  • if x and y is the same number, then return true otherwise return false
msg('NaN === NaN ' + (NaN === NaN));
msg('NaN === 1 ' + (NaN === 1));
msg('1 === NaN ' + (1 === NaN));
msg('isNaN(NaN) ' + isNaN(NaN));
msg('+0 === -0 ' + (+0 === -0));
msg('-0 === +0 '  + (-0 === +0));
msg('12e5 === 12e5 ' + (12e5 === 12e5));
msg('1 === 2 ' + (1 === 2));
typeof x, typeof y are both "boolean"
return true if x and y are either both true or both false otherwise return false.
msg('true === true ' + (true === true));
msg('false === false ' + (false === false));
msg('true === false ' + (true === false));
msg('false === true ' + (false === true));
Strict Does not equal (!==) Operator

return false if left === right is true otherwise return true.

Binary And (&) Operator

Binary And & converts its operands to 32 bit integers, then performs a bitwise And & on the corresponding bits where 1 & 1 is 1 and 0 otherwise.

Example Binary And
msg('1 & 3    == ' + (1 & 3));
msg('1 & 2    == ' + (1 & 2));
msg('0x0f & 0xf0 == ' + (0x0f & 0xf0));
msg('NaN  & 1    == ' + (NaN & 1));
msg('Math.PI & Math.PI == ' + (Math.PI & Math.PI));
Binary XOR (^) Operator

Binary XOR ^ converts its operands to 32 bit integers, then performs a bitwise XOR ^ on the corresponding bits where 1 ^ 1 and 0 ^ 0 is 0 and 1 otherwise.

Example Binary XOR
msg('1 ^ 3    == ' + (1 ^ 3));
msg('1 ^ 2    == ' + (1 ^ 2));
msg('0x0f ^ 0xf0 == ' + (0x0f ^ 0xf0));
msg('NaN  ^ 1    == ' + (NaN ^ 1));
msg('Math.PI ^ Math.PI == ' + (Math.PI ^ Math.PI));
Binary Or (|) Operator

Binary Or | converts its operands to 32 bit integers, then performs a bitwise Or | on the corresponding bits where 0 ^ 0 is 0 and 1 otherwise.

Example Binary Or
msg('1 | 3    == ' + (1 | 3));
msg('1 | 2    == ' + (1 | 2));
msg('0x0f | 0xf0 == ' + (0x0f | 0xf0));
msg('NaN  | 1    == ' + (NaN | 1));
msg('Math.PI | Math.PI == ' + (Math.PI | Math.PI));
Logical And (&&) Operator

returns true if both operands evaluate to true. Note that if the left operand evaluates to false, the right operand is not evaluated (short-circuit evaluation).

msg('true && true ' + (true && true));
msg('true && false ' + (true && false));
msg('false && true ' + (false && true));

// test short-circuit evaluation
var v = 'before';
msg('v == ' + v);
msg('false && ((v = "after") == "after") ' +  
    (false && ((v = "after") == "after")));
msg('v == ' + v);
Logical Or (||) Operator

returns true if either operand evaluate to true. Note that if the left operand evaluates to true, the right operand is not evaluated (short-circuit evaluation).

msg('true || true ' + (true || true));
msg('true || false ' + (true || false));
msg('false || true ' + (false || true));

// test short-circuit evaluation
var v = 'before';
msg('v == ' + v);
msg('true || ((v = "after") == "after") ' +  
    (true || ((v = "after") == "after")));
msg('v == ' + v);
Conditional (?:) Operator

The conditional operator takes three arguments:

condition ? value1 : value2

and returns the value of the expression value1 if condition evaluates to true, otherwise it returns the value of the expression value2.

The precedence of ?: is lower than all other operators except the assignment, compound assignment and the comma operators it is therefore important to properly use the grouping operators (()) to ensure the total expression is evaluated as intended.

// the conditional operator 
msg(' ( (0 % 2) ? true : false) ' + ( (0 % 2) ? true : false));
msg(' ( (1 % 2) ? true : false) ' + ( (1 % 2) ? true : false));

// the equivalent results using if..else
var value;
if (0 % 2)
{
  value = true;
}
else
{
  value = false;
}
msg('0 % 2 is ' + value);
if (1 % 2)
{
  value = true;
}
else
{
  value = false;
}
msg('1 % 2 is ' + value);
Assignment Operators

.

Simple Assignment (=) Operator

The assignment operator = sets the value of its left operand to the value of its right operand. If the left operand has not already been declared or created, it is created at the time of the assigment. Variable created via an assignment without a var declaration do not have {DontDelete} and can be deleted via operator delete.

If the assignment operator is used in a conditional, e.g. if (a = b), Mozilla JavaScript 1.1 - JavaScript 1.2 will treat the = as if it were ==.

var a = 0;
var b = 0;

var result = false;

if (a = b) 
{ 
  result = true; 
}

 msg('(a = b) when a == 0, b ==0 is ' + result);

a = 0;
b = 1;

result = false;

if (a = b) 
{ 
  result = true; 
}

msg('(a = b) when a == 0, b == 1 is ' + result);
msg('afterwards a == ' + a + ', b == ' + b);
Compound Assignment (op=) Operators

The compound assignment left op= right is the equivalent for the expression

left = left op right

where op is one of *, /, %, -, <<, >>, >>>, &, ^ or |.

Comma (,) Operator

The comma operator , is used to evaluate a sequence of expressions, returning the value of the last expression as the value of the entire comma expression.

For example, if the expression is expr1, expr2, expr3, expr1 is evaluated, expr2 is evaluated then expr3 is evaluated and the value of expr3 is returned.

var value = 0;
msg('The value of (value += 1, value += 2, value += 3) is ' +
    (value += 1, value += 2, value += 3));
JavaScript Statements
Block Statement

A Block statement is a set of one or more other statements which are surrounded by braces {} in order to be treated as a group of statements. Block statements can be used anywhere a single statement can be used.

{
  statement1
  statement2
  …
}

Block statements are typically used as the bodies of for, while, or if statements.

Note that unlike C or Java, there is no block scope in JavaScript. Variables declared inside of block statements do not hide variables declared outside of the block nor do variables declared inside of block statements cease to exist when the block statement is exited.

// declare and initialize a variable outside of the 
// block statement.
var variable = 'outside';
if (true)
{
  // declare the same variable inside of the block
  // statement. This does not hide the outside variable
  // which remains unchanged from the outside value.
  var variable;
  msg('variable inside block == ' + variable);
}
var Statement

A var statement creates variables in the current execution scope. If the var statement occurs inside of a function, the declared variables are created in function scope with property attribute {DontDelete}, otherwise they are created in global scope with property attribute attribute {DontDelete}. Variables created via the eval function are created with empty property attributes. See delete Operator for implementation differences in the delete operator. Note that the with statement does not affect the scope when creating variables.

The var statement is written as a comma-separated list of variable names and optional initializers which is terminated by a semi-colon (;).

// simple variable declaration of name1, 
// initialized to undefined
var name1; 

// simple variable declaration of name2,
// initialized to 'value2'
var name2 = 'value2';

// declaration of the variables name3, name4, name5
// with the value of name4 initialized to 'value4'
var name3, name4 = 'value4', name5;

Example Delete Global Scope Variable

var globalVar = 'value';
msg('typeof globalVar == ' + (typeof globalVar));
msg('delete globalVar == ' + (delete globalVar));
msg('typeof globalVar == ' + (typeof globalVar));

Global variables have property attribute {DontDelete} which means that they can not be deleted however any such attempt should not cause an error

Mozilla JavaScript1.1 and JavaScript1.2 will throw an error when attempting to delete a global variable.

Example Delete Function Scope Variable

function testFunctionVarDelete()
{
  var functionVar = 'value';
  msg('typeof functionVar == ' + (typeof functionVar));
  msg('delete functionVar == ' + (delete functionVar));
  msg('typeof functionVar == ' + (typeof functionVar));
}

testFunctionVarDelete();

Variables created in function scope have property attribute {DontDelete} which means that they can not be deleted and any such attempt should not cause an error. Note that Mozilla JavaScript1.1 and JavaScript1.2 do not throw an error when an attempt to delete a function scope variable is made.

Example Delete Eval Scope Variable

eval('var evalVar = "value";');
msg('typeof evalVar == ' + (typeof evalVar));
msg('delete evalVar == ' + (delete evalVar));
msg('typeof evalVar == ' + (typeof evalVar))

Variables created in via eval have empty internal attributes which means that they can be deleted.

Note that Mozilla JavaScript1.1, JavaScript1.2 successfully delete eval scope variables however returns undefined for delete instead of boolean.

const Statement

Mozilla Only

A const statement creates variables in the current execution scope with property attribute {ReadOnly} which means it can not be changed. If the const variable is created in global or function scope it also has property attribute {DontDelete} which means it can not be deleted.

Example Modifiy Const

try
{
  eval('const a = 1;');
  msg('const a == ' + a);
  try
  {
    a = 2;
    msg('a should still be 1, a == ' + a);
  }
  catch(e)
  {
    msg('Error assigning to const var.' +  
      e.name + ': ' + e.message);
  }
}
catch(e)
{
  msg('Error during const declaration.' +  
      e.name + ': ' + e.message);
}

Note that Mozilla JavaScript1.1 and JavaScript1.2 will throw an error if a const is the target of an assignment however Mozilla JavaScript1.3 and later will not.

Example Delete Global Scope Const Variable

const globalVar = 'value';
msg('typeof globalVar == ' + (typeof globalVar));
msg('delete globalVar == ' + (delete globalVar));
msg('typeof globalVar == ' + (typeof globalVar));

Global const variables have property attributes {ReadOnly} and {DontDelete} which means that they can not be changed or deleted however any such attempt should not cause an error however Mozilla JavaScript1.1 and JavaScript1.2 will throw an error.

Example Delete Function Scope Const Variable

function testFunctionConstDelete()
{
  const functionVar = 'value';
  msg('typeof functionVar == ' + (typeof functionVar));
  msg('delete functionVar == ' + (delete functionVar));
  msg('typeof functionVar == ' + (typeof functionVar));
}

testFunctionConstDelete();

Constant Variables created in function scope have property attribute {ReadOnly} and {DontDelete} which means that they can not be changed or deleted and any such attempt should not cause an error. Note that Mozilla JavaScript1.1 and JavaScript1.2 do not throw an error when an attempt to delete a function scope variable is made.

Example Delete Eval Scope Const Variable

eval('const constVar = "value";');
msg('typeof evalVar == ' + (typeof evalVar));
msg('delete evalVar == ' + (delete evalVar));
msg('typeof evalVar == ' + (typeof evalVar));

Const variables created via eval have property attribute {ReadOnly} which means that they can not be changed but can be deleted.

Note that Mozilla JavaScript1.1, JavaScript1.2 successfully delete eval scope variables however returns undefined for delete instead of boolean.

Empty Statement

The empty statement is written as a single semi-colon (;) and is used when a statement is required by the syntax but is unnecessary otherwise.

;
Expression Statement

Expression statements are written as:

Expression;

Where Expression can not begin with a brace { or function.

Conditional Statements
The if Statement

The if Statement is used to conditionally execute sections of code. The basic form is:

if (conditional) 
  Statement1

The conditional expression is evaluated and converted to a boolean value. If the result is true, Statement1 is executed otherwise Statement1 is skipped.

msg('test if true');
if (true)
  msg('this statement will be executed');

msg('test if false');
if (false)
  msg('this statement will not be executed');

The other form of the if Statement is

if (conditional) 
  Statement1 
else
  Statement2

In this case, if conditional evaluates to true, then Statement1 is executed, otherwise Statement2 is executed.

msg('test if true');
if (true)
  msg('this statement will be executed');
else 
  msg('this statement will not be executed');

msg('test if false');
if (false)
  msg('this statement will not be executed');
else 
  msg('this statement will be executed');

if statements can be combined to create multi-level tests as in:

if (conditional1)
  Statement1
else if (conditional2)
  Statement2
else if (conditional3)
  Statement3

In cases such where there is a dangling else

if (conditional0)
  if (conditional1)
    Statement1
  else
    Statement2

The else binds to the closest if as in:

if (conditional0)
{
  if (conditional1)
    Statement1
  else
    Statement2
}

Braces {} can be used to make it clear how a nested if statement should be executed and can make the code clearer for human readers as well.

msg('without braces');
if (true)
  if (false)
    msg('this statement will not be executed');
  else
    msg('this statement will be executed');

msg('with braces');
if (true)
{
  if (false)
    msg('this statement will not be executed');
  else
    msg('this statement will be executed');
}
The switch Statement

The switch statement is used to execute one of a set of possible statements depending on the value of an expression and has the form:

switch (switchexpression)
{
  case caseexpression1:
    statement1
    break;

  case caseexpression2:
    statement2
    break;

   …

   default:
     defaultstatement
     break;
}

switchexpression is evaluated then each case expression caseexpression is evaluated and compared to the switchexpression using strict equality until a match is found. Once a matching caseexpression is found, the statements following up to the following break statement are executed. If the break statement is not present, the statements following the case statement are executed until either a break is encountered or the switch statement is completed.

The above example is equivalent to the following nested if statement (note the use of strict equality testing):

if (switchexpression === caseexpression1)
{
  statement1
}
else if (switchexpression === caseexpression)
{
  statement2
}
…
else 
{
  defaultstatement
}
// illustrate a basic switch with strict equality
switch (2 * 3)
{
  case '6':
    msg('this statement will only be executed ' + 
        'if strict equality is not used');
    break;

  case 6:
    msg('this statement should be executed');
    break;

  default:
    msg('this statement is only executed ' +
        'if no case expression is satified');
    break;
}

If you do not code a break statement, the execution will fall through continuing to execute case blocks until a break is encountered.

// illustrate a switch with fall through
switch (2 * 3)
{
  case '6':
    msg('this statement will only be executed ' + 
        'if strict equality is not used');
    break;

  case 6:
    msg('this statement should be executed');
    // no break means fall through to the next statement

  default:
    msg('this statement is executed ' +
        'since no break was coded for case 6');
    break;
}

While the break statement is not strictly necessary when the default statement is the last block of the switch, it is good practice to code it in the event that at some future date, a programmer changes the switch by adding another case block after the default block.

Iteration Statements

Iteration statements are used to repeatedly execute a set of statements while a condition is true (the while, do while, for statements) to iterate over the properties of an object (for in statement). The special statements break and continue along with labelled statements allow transfers of control similar to that of the goto statement in other languages. Note that there is no goto statement in JavaScript.

The while Statement
while (conditional)
  Statement

The while statement is used to repeatedly execute a set of statements while a condition evaluates to true.

var i = 0;
while (i < 5)
{
  msg('while: i == ' + i + ', i < 5 == ' + (i < 5));
  ++i;
}
The do-while Statement
do 
  Statement
while (conditional);

The do while statement is used to repeatedly execute a set of statements until a condition evaluates to false.

var i = 0;
do
{
  msg('while: i == ' + i + ', i < 5 == ' + (i < 5));
  ++i;
} while (i < 5);

Note that unlike while, the do while will execute Statement at least once regardless of the value of conditional since the test occurs after Statement is executed.

do
{
  msg('do while is always executed at least once');
} while (false);
The for Statement

for (init; condition; increment)
  Statement

The for statement is a convenience statement for a commonly used form of while statement of the form:

init;
while(condition)
{
  Statement
  increment;
}

and is particularly useful for iterating over the elements of an Array.

The for-in Statement
for (propname in object)
  Statement

for in is used to iterate over the enumerable properties in an object instance. The body of the for loop is executed with the variable propname set to each of the enumerable properties in the object. Properties with property attribute {DontEnum} are not discoverable using the for in statement.

var object = {a: 'a', b: 'b' };
for (var prop in object)
{
  msg('object.[\'' + prop + '\'] == ' + object[prop]);
}
Labelled Statements
label : LoopStatement

label must be an identifier and LoopStatement must be one of the while, for or for-in interation statements. Labelled statements are used to mark loops which are the destination of continue or break statements.

The continue Statement
continue

or

continue label;

A continue statement is used to restart a loop statement either at the beginning of the currently executing loop or at the beginning of a loop whose location is specified by the labelled statement marked by the label label.

msg('test basic continue');
for (var i = 0; i < 3; i++)
{
  msg('before continue: i == ' + i);
  continue;
  msg('after continue: this statement will not be executed');
}
msg('test labelled continue');
label0: for (var i = 0; i < 3; i++)
{
  msg('loop0: i == ' + i);
  label1: for (var j = 0; j < 3; j++)
  {
    msg('loop1: i == ' + i + ', j == ' + j);
    if (i == j)
    {
      msg('continue from label0');
      continue label0;
    }
    else
    {
      msg('continue from label1');
      continue label1;
    }
  }
}
The break Statement
break
or
break label

A break statement is used to terminate either the currently executing loop or the loop whose location is specified by the labelled statement marked by the label label.

msg('test basic break');
for (var i = 0; i < 3; i++)
{
  msg('before break: i == ' + i);
  break;
  msg('after break: this statement will not be executed');
}
msg('test labelled break');
label0: for (var i = 0; i < 3; i++)
{
  msg('loop0: i == ' + i);
  label1: for (var j = 0; j < 3; j++)
  {
    msg('loop1: i == ' + i + ', j == ' + j);
    if (i == j)
    {
      msg('break from label0');
      break label0;
    }
    else
    {
      msg('break from label1');
      break label1;
    }
  }
}
Exception Statements

JavaScript provides the ability to handle errors and other exceptions through the use of the exception handling statements try, catch and finally. When an error or other run-time exception occurs in JavaScript the interpreter unwinds the execution stack looking for a try block which contains the code which caused the error. If a try block is found, the interpreter transfers control of the program to the matching catch block of statements passing an exception object thereby allowing the program to investigate the error and possibly recover. If no containing try statement block is found, the program will terminate with an "uncaught exception" error.

Although try, catch, throw were not introduced until after ECMAScript 2, Mozilla JavaScript1.1 and JavaScript1.2 still support these statements.

Web browsers such as Mozilla and Internet Explorer also provide the ability to handle errors at the top level of a program through the use of the window.onerror handler which is a user-defined function which takes arguments message, line and page indicating the error message, the line number and file where the error occured. window.onerror is available in the earliest implementations of JavaScript in Web browsers however its inability to recover from errors gracefully limits its usefulness to handling errors that have not been caught by the techiniques available using try/catch error handling.

The try, catch and finally Statements

Example Try, Catch Reference Error

try
{
  // cause reference error
  var a = b;
}
catch(e)
{
  msg('Exception caught: ' +  
      e.name + ': ' + e.message);
}

In this example, the try block contains a statement var a = b; which attempts to assign an undefined variable b to the variable a. This will cause a Reference Error in JavaScript which would terminate the program if it were not contained in a try block. Once the error occurs, control is transferred to the catch block of statements and the variable e is initialized to reference the Error object describing the error.

Mozilla's implementation of the Error object provides a version of the toString() method which displays a human readable error message containing the type of error which occured and the error message as in ReferenceError: b is not defined however MSIE simply displays [object Error].

MSIE's implementation of the Error object can be modified to report a human readable error message similar to Mozilla's. For example,

// override MSIE's Error.prototype.toString
if (typeof (new Error).number == 'number')
{
  // number is an MSIE only property
  Error.prototype.toString = function () 
  {
    return this.name + ': ' + this.message;
  };
}

try
{
  var a = b;
}
catch(e)
{
  msg(e);
  msg('e instanceof ReferenceError == ' + (e instanceof ReferenceError));
}

Note the difference between Mozilla and MSIE: Mozilla returns a ReferenceError while MSIE returns a TypeError.

Note that there is no var declaration of the exception variable e in the above example. This due to the special scoping rules for catch clauses. In JavaScript, the exception variable passed to the catch block only exists inside of the catch block itself.

MSIE creates the exception object in the containing scope of the catch block and not as part of the catch block's scope.

function test()
{
  var e = 'function scope';
  msg('test() before try: e == ' + e);
  try
  {
    var a = b; 
  }
  catch(e)
  {
    msg('test() catch:  e ==  ' +  e);
  }
  msg('test() after catch: e == ' + e);
}

var e = 'global scope';

msg('Before test(): e == ' + e);
test();
msg('After test(): e == ' + e);

As you can see, Mozilla sets the variable e to the Error object only inside of the catch block while MSIE sets e to the Error object even after the catch block has finished.

The finally block of statements is executed after the try or catch blocks regardless whether an error occured or not.

// no error
try
{
  var a = 1;
}
catch(e)
{
  msg('Exception caught: ' + e);
}
finally
{
  msg('Finally clause');
}
// thrown exception
try
{
  throw 'exception';
}
catch(e)
{
  msg('Exception caught: ' + e);
}
finally
{
  msg('Finally clause');
}

Mozilla supports the use of conditionals to select the catch clause however Mozilla JavaScript1.1, JavaScript1.2 can not use the instanceof operator since it is not supported. MSIE does not support conditional catch clauses.

// Use conditional catch clauses without instanceof
// This example will work in all versions of Mozilla JavaScript
try
{
  throw 'string exception';
}
catch(e if typeof e == 'number')
{
  msg('Number exception ' + e);
}
catch(e if typeof e == 'string')
{
  msg('String exception ' + e);
}
catch(e)
{
  msg('Exception caught: ' + e);
}
finally
{
  msg('Finally clause');
}
// Use conditional catch clauses with instanceof
// This example will work in all versions of Mozilla JavaScript1.3 and later
try
{
  var a = b;
}
catch(e if e instanceof String)
{
  msg('String exception ' + e);
}
catch(e if e instanceof ReferenceError)
{
  msg('ReferenceError caught: ' + e);
}
finally
{
  msg('Finally clause');
}
The throw Statement
throw exception

The throw statement simulates an error condition and passes the value of the exception expression to the catch clauses as the value of the exception variable. The exception value can be any object including an instance of an Error object created via the new operator.

try
{
  throw 'thrown exception';
}
catch(e)
{
  msg('Exception caught: ' + e);
}

Mozilla 1.7 and earlier allow an newline after throw and before exception in violation of the ECMA 262 Standard. See ECMA 262 - The throw statement. Mozilla 1.8 (Firefox 1.1) will correctly throw an error in this situation.

MSIE correctly throws an error.

throw
'exception';
JavaScript Native Objects

JavaScript provides a number of native (built-in) objects which serve as a standard library. These native objects are the global object and the initial (prior to programs creating new properties) properties of the global object.

Native JavaScript objects come in two types:

Function type objects

Function type objects are those which have typeof object == 'function' and can be called as functions (object()). Function type objects have an internal prototype property which is initially set to the value of Function.prototype. This prototype property may or may not (depending on the function) be available as an accessible property prototype.

Some Function type objects also have the ability to be used a constructors which when operated on by the new operator return instances of the object. Function type objects which can be used as constructors have an internal constructor property which may or may not be accessible as the constructor property.

Every Function type object has a property length which is defined to be {ReadOnly}, {DontDelete} and {DontEnum}. length is defined to be the maximum number of properties for the Function type. This implies that the length property of Function type objects can not be modified or removed by a JavaScript program.

MSIE treats the length property of Function type objects as the number of non-optional arguments instead of the maximum number.

Object type objects

Object type objects are those which have typeof object == 'object' and which can not be called as functions.

Object type objects can not be used as constructors.

Every other property of native JavaScript objects are specified to be {DontEnum} unless noted otherwise. This means that these properties can be removed, or redefined by an executing JavaScript program.

Many of the native JavaScript objects are constructors which can be used to create instances of the objects. Some methods (as noted below) can be transferred to other objects and reused in different contexts. These methods are called generic methods. Non-generic methods are tied to their original types and will throw a TypeError if used with a different type object.

JavaScript Native Object constructor names are written with the initial letter capitalized. For example, Object, String and Date are all native Object contructors. In the following, any native and user-defined constructor names will be written as Object, String and Date, etc. When referring to instances of these constructors, they will be written using the constructor name in all lower case as object, string and date, etc..

For example, let Example be a constructor.

Example
the constructor object
example
an instance of Example, e.g. example = new Example().
Example.prototype.sharedProperty
some shared property of instances of Example, e.g. example.hasOwnProperty('sharedProperty') == false.
Example.localProperty
some local property of Example, e.g. Example.hasOwnProperty('localProperty') == true.
example.someProperty
some local property of example, e.g. example.hasOwnProperty('localProperty') == true.
The Global Object

The Global object is not accessible by name, can not be used in function calls or as a constructor. It is used as the root of the scope chain when resolving variable references. That means that variables created in global scope (outside of any function bodies) are created as properties of the global object.

In Web browsers such as Mozilla and Internet Explorer, the global object is the window object.

NaN

NaN is a special numeric value (typeof NaN == 'number') which respresents the Not a Number values in the IEEE Standard for binary numbers.

NaN has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value.

Note that NaN compares as not equal to itself as well as any other number. In order to test a number for equality with NaN use the global isNaN(value) function which returns true if value is NaN.

msg('typeof NaN == ' + typeof NaN);
msg('(NaN == NaN) == ' + (NaN == NaN));
msg('(NaN === NaN) == ' + (NaN === NaN));
msg('isNaN(NaN) == ' + isNaN(NaN));
Infinity

Infinity is a special numeric value (typeof NaN == 'number') which represents a numeric value which is greater than any other numeric value except NaN.

Infinity has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value.

msg('typeof Infinity == ' + typeof Infinity);

msg('(10000000000000000000 < Infinity) == ' + 
    (10000000000000000000 < Infinity));

msg('(NaN < Infinity) == ' + (NaN < Infinity));
undefined

undefined is the single value of the type Undefined (typeof undefined == 'undefined') and it used to represent uninitialized values.

undefined has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value.

eval(x)

eval(x) is a function property (method) of the Global Object which compiles and executes the string x as a JavaScript program.

eval has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value. If x contains a syntax error, a SyntaxError will be thrown.

// compile an expression to add two numbers
msg('eval(\'1 + 2\') == ' + eval('1 + 2'));

// compile an expression with a syntax error
try
{
  eval('var 0 = 1;');
}
catch(e)
{
  msg('Error ' +  
      e.name + ': ' + e.message + 
      ' is an instance of SyntaxError: ' + 
      (e instanceof SyntaxError));
}

Mozilla and MSIE allow eval to be used indirectly and to be the object of an assignment. This is supported by the ECMA 262 Standard Section 16. Errors so long as EvalError is not thrown.

// test if implementation throws EvalError when
// eval is used indirectly.
try
{
  var myeval = eval;
  msg('myeval(\'1+1\') == ' + myeval('1+1'));
}
catch(e)
{
  msg('eval can not be used indirectly. ' +  
      e.name + ': ' + e.message);
}

// test if implementation throws EvalError when
// eval is used as a variable.
try
{
  var eval = function (s) { msg('redefined eval: ' + s); };
  msg('eval(\'1+1\') == ' + eval('1+1'));
}
catch(e)
{
  msg('eval can not be reassigned. ' +  
      e.name + ': ' + e.message);
}

Mozilla JavaScript 1.2 generates an error "invalid label" when attempting to eval("({})").

try
{
  eval( '({})' );
  msg('No error');
}
catch(e)
{
  msg('Exception: ' +  
      e.name + ': ' + e.message);
}
parseInt(string, radix)

parseInt(string, radix) is a function property (method) of the Global Object which parses string converting it to a numeric integer value using base radix. Any leading whitespace in string is skipped. If radix is undefined or 0, then radix is assumed to be 10. If string is not parseable as an integer, NaN is returned.

parseInt has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value.

function test(expr)
{
  var value = eval(expr);
  msg('typeof ' + expr + ' == ' + (typeof value) + 
    ', ' + expr + ' == ' + value);
}

test('parseInt("  10")');
test('parseInt("  10", 2)');
test('parseInt("  20x")');
test('parseInt("y20x")')
parseFloat(string)

parseFloat(string) is a function property (method) of the Global Object which parses string converting it to a numeric value using base 10. Any leading whitespace in string is skipped. If string is not parseable as an floating point number, NaN is returned.

parseFloat has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value.

function test(expr)
{
  var value = eval(expr);
  msg('typeof ' + expr + ' == ' + (typeof value) + 
    ', ' + expr + ' == ' + value);
}

test('parseFloat("  10")');
test('parseFloat("  10", 2)');
test('parseFloat("  20x")');
test('parseFloat("y20x")')

test('parseFloat("123.456")');
test('parseFloat("123e4")');
isNaN(number)

isNaN(number) is a function property (method) of the Global Object which returns true if number is NaN or convertable to NaN, false otherwise.

isNaN has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value.

msg('isNaN(NaN) == ' + isNaN(NaN));
msg('isNaN("foo") == ' + isNaN("foo"));
isFinite(number)

isFinite(number) is a function property (method) of the Global Object which converts number to a numeric value then returns true if the value is not Infinity. number values which are NaN or are convertable to NaN return false.

isFinite has property attributes {DontEnum} and {DontDelete} which means it will not appear in for-in loops and can not be deleted, but can be changed to another value.

msg('isFinite(10) == ' + isFinite(10));
msg('isFinite(Infinity) == ' + isFinite(Infinity));
msg('isFinite("NaN") == ' + isFinite("NaN"));
msg('isFinite("foo") == ' + isFinite("foo"));
encodeURI(uri) and decodeURI(encodedURI)

encodeURI(uri) and decodeURI(encodedURI) are functions properties (methods) of the Global Object which are used encode and decode complete URI values by mapping special characters to their % escaped character equivalents. encodeURI and decodeURI have property attributes {DontEnum} and {DontDelete} which means they will not appear in for-in loops and can not be deleted, but can be changed to another value.

Since the uri value is assumed to be a complete URI, the characters ; / ? : @ & = + $ , - _ . ! ~ * ' ( ) which have special meanings in URIs are left unchanged.

function test(URI)
{
  var encoded = encodeURI(URI);
  var decoded = decodeURI(encoded);

  msg('URI == "' + URI + '"');
  msg('encoded == "' + encoded + '"');
  msg('decoded == "' + decoded + '"');
  msg('(URI == encoded) == ' + (URI == encoded));
  msg('<br>');
}

// test space, percent, backquote
test(' %`');

// test unicode characters
test('\u092F\u0942\u0928\u093F\u0915\u094B\u0921');

// test invariant special characters
test(";/?:@&=+$,-_.!~*'()");

// test digits
test('0123456789');

// test latin letters
test('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');

encodeURIComponent(uriComponent) and decodeURIComponent(encodedURIComponent)

encodeURIComponent(uriComponent) and decodeURIComponent(encodedURIComponent) are functions properties (methods) of the Global Object which are used encode and decode partial URI values by mapping special characters to their % escaped character equivalents. encodeURIComponent and decodeURIComponent have property attributes {DontEnum} and {DontDelete} which means they will not appear in for-in loops and can not be deleted, but can be changed to another value.

Since the uriComponent value is assumed to be a a component of a URI, the characters ; / ? : @ & = + $ , which have special meanings in URIs are not left unchanged and are mapped to their % escaped equivalents. The special characters - _ . ! ~ * ' ( ) are left unchanged.

function test(URI)
{
  var encoded = encodeURIComponent(URI);
  var decoded = decodeURIComponent(encoded);

  msg('URI == "' + URI + '"');
  msg('encoded == "' + encoded + '"');
  msg('decoded == "' + decoded + '"');
  msg('(URI == encoded) == ' + (URI == encoded));
  msg('<br>');
}

// test space, percent, backquote
test(' %`');

// test unicode characters
test('\u092F\u0942\u0928\u093F\u0915\u094B\u0921');

// test invariant special characters
test("-_.!~*'()");

// test other special characters
test(";/?:@&=+$,");

// test digits
test('0123456789');

// test latin letters
test('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
              
Object(…)
Function(…)
Array(…)
String(…)
Boolean(…)
Number(…)
Date(…)
RegExp(…)
Math
Error(…)
EvalError(…)
RangeError(…)
ReferenceError(…)
SyntaxError(…)
TypeError(…)
URIError(…)
Object Objects

Object Objects can be created using the Object(value) constructor or using literal Object initializers.

Creating Object Objects

var object;

// create an instance of Object using the constructor
object = new Object();

// create an instance of Object using a literal initializer
object = {};

If Object(value) is called as a function, it performs a conversion of value to Object.

Object Objects are special in that serve as the base class for all native and user-defined JavaScript objects.

var types = [Object, Function, Array, String, Boolean, Number,
             Date, RegExp, Error];
for (var i = 0; i < types.length; i++)
{
  msg(types[i] instanceof Object);
}

The fact that all native and user-defined objects inherit from Object means that they share Object's methods and if modifications are made to Object.prototype, then all native and user-defined objects automatically share those modifcations.

Example showing how methods are inherited from Object

// add fooBar as a method to Object.prototype
Object.prototype.fooBar = function ()
{
  msg('FOOBAR!');
};

var date = new Date();
date.fooBar();
Object([value])

The Object function can be called either as a constructor or as a function.

Object has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete Object
msg('Before delete: typeof Object == ' + typeof Object);
msg('(delete Object) == ' + (delete Object));
msg('After delete: typeof Object == ' + typeof Object);
// attempt to assign to Object
Object = 'foo';
msg('After Object = \'foo\': Object == ' + Object);

When called as a constructor with no value argument it will create an empty instance of Object with prototype Object.prototype, with its internal Class property set to 'Object'. When called with a value which is not a native or user-defined JavaScript Object, the constructor returns the value converted to Object. When called with a value which is a native or user-defined Object, the constructor returns value without creating a new object instance.

var object1;
var object2;

// create an empty instance of Object
object1 = new Object();
msg('typeof object1 == ' + typeof object1);

// convert primitive values to Objects
object1 = new Object('foo');
msg('typeof object1 == ' + typeof object1);
msg('(object1 == "foo") == ' + (object1 == "foo"));

// call with object value returns the same
// object
object2 = new Object(object1);
msg('(object1 === object2) == ' + (object1 === object2));
Object.prototype

Object.prototype defines the base properties and methods for all native and user-defined JavaScript objects. Although Object.prototype.toString() returns "[object Object]", Object.prototype is not an Object. Object.prototype.prototype is undefined which means it does not inherit properties or methods from any other object.

msg('Object.prototype == ' + Object.prototype);
msg('Object.prototype instanceof Object ' + 
    (Object.prototype instanceof Object));
msg('Object.prototype.prototype == ' + Object.prototype.prototype);

Object.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

Object.prototype.constructor

contains a reference to the constructor function Object used to create the instance.

Object.prototype.toString()

returns a string representing the instance. For instances of type Object, toString returns '[object Object]' however the actual value can vary depending on whether the instance is a native object, a user-defined object or a host object.

In Mozilla JavaScript1.2, toString()a behaves like toSource() below.

The ECMAScript standard specifies that for native JavaScript Objects, toString() should return a string of the form '[object Class]' where Class is the name of the object's constructor however MSIE generates "[object]" for host objects. You can get native built-in objects like Date, RegExp to report "[object Date]", "[object RegExp]" by Native.prototype.getClass = Object.prototype.toString; then calling getClass on an instance. This does not work for user defined objects however.

// define a getClass method based 
// on Object.prototype.toString. Note 
// Native JavaScript objects will inherit this
// method but Host Objects will not.
Object.prototype.getClass = Object.prototype.toString;

// test native objects
var d = new Date();
var s = new String();
msg('d.toString() == ' + d.toString() + 
    ', d.getClass() == ' + d.getClass());
msg('s.toString() == ' + s.toString() + 
    ', s.getClass() == ' + s.getClass());

// test host objects
try
{
  // this will cause an error since the host object
  // window does not inherit from Object
  msg('window.toString() == ' + window.toString() + 
      ', window.getClass() == ' + window.getClass());
}
catch(e)
{
  msg('Error ' +  
      e.name + ': ' + e.message);

  // set the getClass method directly on window
  window.getClass = Object.prototype.toString;
  msg('window.toString() == ' + window.toString() + 
      ', window.getClass() == ' + window.getClass());
}
Object.prototype.toSource()

Mozilla only function which returns a string representing the Object Initializer. This is overridden by child classes of Object to perform specialized source output.

var object = {prop1: 'value1', prop2: 'value2'};
try
{
  msg('object.toSource() = ' + object.toSource());
}
catch(e)
{
  msg('Error object.toSource not supported ' +  
      e.name + ': ' + e.message);
}

When called on a function, toSource returns the source code of the function if it is user-defined and a dummy function with '[native code]' as the body when the function is native.

function Object() { 
  [native code]
  }
                  
try
{
  msg('Object.toSource() == ' + Object.toSource());
}
catch(e)
{
  msg('Error toSource not supported ' +  
      e.name + ': ' + e.message);
}
Object.prototype.toLocaleString()

returns a localized string representing the instance.

Object.prototype.valueOf()

returns the this value for the instance.

Object.prototype.hasOwnProperty(property)

returns true if property is a local (unshared) property of the instance.

Object.prototype.isPrototypeOf(object)

returns true if the instance is the prototype of object.

Object.prototype.propertyIsEnumerable(property)

returns true if property is enumerated during a for (p in instance) loop.

Object.prototype.eval(source)

Evaluates source placing the object instance at the front of the scope chain.

Object.prototype.eval is supported in Mozilla but not MSIE

try
{
  var o = {v: 'object scope' };
  msg('eval v in scope of object == ' + o.eval('v'));
}
catch(e)
{
  msg('Error Object.prototype.eval not supported ' +  
      e.name + ': ' + e.message);
}
Object.name

Mozilla provides a local property name on the Object constructor (as well as other native and user-defined constructors) which returns a string containing the name of the constructor function.

msg('Object.name == ' + Object.name);
Object.length

Object has one optional argument value, therefore Object.length is 1.

msg('Object.length == ' + Object.length);

MSIE returns Object.length == 0 since it does not report optional arguments.

object.__proto__

Mozilla implements a local property __proto__ in each instance of an object which points to its prototype object. This allows easy access to an instance's prototype. This property is not supported by MSIE.

var object = new Object();

// Mozilla only
msg('object.__proto__ == ' + 
    object.__proto__);
msg('object.__proto__.toString == ' + 
    object.__proto__.toString);

// cross browser emulation of __proto__
msg('getPrototype(object) == ' + 
     getPrototype(object));
msg('getPrototype(object).toString == ' +
     getPrototype(object).toString);
msg('getPrototype(object) == object.__proto__ == ' +
    (getPrototype(object) == object.__proto__));

function getPrototype(o)
{
  try
  {
    return o.constructor.prototype;
  }
  catch(e)
  {
  }
  return null;
}
  
Example Create_Object_Constructor
// create an object using a Constructor
var object = new Object();

// test the existence of the standard shared properties
msg('object.constructor '    + object.constructor);
msg('object.toString '       + object.toString);
msg('object.toLocaleString ' + object.toLocaleString); 
msg('object.valueOf '        + object.valueOf); 
msg('object.hasOwnProperty ' + object.hasOwnProperty); 
msg('object.isPrototypeOf '  + object.isPrototypeOf);
msg('object.propertyIsEnumerable '   + object.propertyIsEnumerable);

// add properties to the object
object.property1 = 'value1';
object.property2 = 'value2';

// loop over the properties of the object
// displaying the enumerable property names and values
for (var propname in object)
{
  msg('object\'s property "' + propname + 
      '" is "' + 
      object[propname] + '"');
}

// test if a property exists
if ('property1' in object)
{
  msg('object.property1 exists');
}

// test if a property is local
if ('hasOwnProperty' in object)
{
  msg('object has local property property1 ' + 
      object.hasOwnProperty('property1'));
  msg('object has local property constructor ' +
      object.hasOwnProperty('constructor'));
}

// test if a property is enumerable
if ('propertyIsEnumerable' in object)
{
  msg('object.property1 is enumerable ' + 
      object.propertyIsEnumerable('property1'));
  msg('object.constructor is enumerable ' + 
      object.propertyIsEnumerable('constructor'));
}
Function Objects

All JavaScript functions are instances of the Function Object and have typeof function == 'function'. Function objects can be created using the Function constructor, as function definitions, or as function expressions.

Creating Function Objects

// create a function using function definition
function funcdef(arg1, arg2)
{
  return arg1 + arg2;
}
msg('typeof funcdef == ' + typeof funcdef);

// create a function using a function expression
var funcexpr = function _funcexpr(arg1, arg2) { return arg1 + arg2;};
msg('typeof funcexpr == ' + typeof funcexpr);

// create a function using new Function
var funcnew = new Function("arg1", "arg2", "return arg1 + arg2;");
msg('typeof funcnew == ' + typeof funcnew);

// create a function using Function call
var funccall = Function("arg1", "arg2", "return arg1 + arg2;");
msg('typeof funccall == ' + typeof funccall);
Function(arg1, arg2, …)

The Function constructor can be called equivalently as a constructor new Function(…) or as a simple function call Function(…). The return value of Function is a reference to a function instance which can be called like any other function.

Function has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete Function
msg('Before delete: typeof Function == ' + typeof Function);
msg('(delete Function) == ' + (delete Function));
msg('After delete: typeof Function == ' + typeof Function);
// attempt to assign to Function
Function = 'foo';
msg('After Function = \'foo\': Function == ' + Function);

Function() takes any number of string arguments. The last argument is always considered to be a string containing the body of the function while the other arguments are considered to be the list of argument names for the function. Note that the arguments to the new function can be written separately as "arg1", "arg2", … or as a single string "arg1, arg2, …". For example, the following are equivalent:

func = new Function("arg1", "arg2", "return arg1 + arg2;")
func = new Function("arg1, arg2", "return arg1 + arg2;")
function func(arg1, arg2) {return arg1 + arg2;}
Function.prototype

Function.prototype defines the shared properties and methods of all instances of Function inherit. Function.prototype is an instance of Object which means instances of Function inherit from Object.

msg('Function.prototype == ' + Function.prototype);
msg('Function.prototype.prototype == ' + Function.prototype.prototype);

Function.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

Function.prototype.constructor

returns the Function constructor.

Function.prototype.toString()

Returns a string representing the source code of the function instance. For native functions, returns '[native code]' for the function body.

msg('Function.toString() == ' + Function.toString());

function userDefined(arg1, arg2)
{
  return arg1 + arg2;
}

msg('userDefined.toString() == ' + userDefined.toString());

if ('toSource' in userDefined)
{
  msg('userDefined.toSource() == ' + userDefined.toSource());
}
Function.prototype.toSource()

Mozilla only function which returns the source code of the function instance. See Function.prototype.toString.

Function.prototype.apply(thisArg, argArray)

Calls the function as if it were a method of the thisArg instance with arguments argArray[0], argArray[1], …. If thisArg is undefined or null, the global object is passed as the value of thisArg.

Function.prototype.call(thisArg[, arg1 [, arg2, …]])

Calls the function as if it were a method of the thisArg instance with arguments arg1, arg2, …. If thisArg is undefined or null, the global object is passed as the value of thisArg.

Function.length

returns 1

msg('Function.length == ' + Function.length);
function.length

Returns the number of defined arguments for the function instance.

Mozilla JavaScript1.1, JavaScript1.2 will report function.length to be the actual number of arguments passed to the function rather than the defined number of arguments. This is not the case for Mozilla JavaScript1.3 or later. See Example Function_Call_Context.

function.arity

A Mozilla extension function.arity returns the same value as function.length. This is not supported by MSIE

function f(arg0, arg1)
{
  msg('f.length == ' + f.length + 
      ' arguments.length == ' + arguments.length + 
      ' f.arity  == ' + f.arity);
}

f(1);
function.prototype

The prototype property of function instances is used as the prototype object for objects created from using the function as a constructor.

function.name

Mozilla implements a property on instances of Function which returns the name of the function. Anonymous functions created via new Function() return 'anonymous' while Anonymous functions created by function expressions return ''. Note that Mozilla JavaScript1.1, JavaScript1.2 return '' for both types.

Mozilla supports the name property of constructor objects in Function prototypes. This always returns 'Function'. MSIE does not support this property.

function myfunction()
{
}

msg('myfunction.constructor.name ==' + 
    myfunction.constructor.name);
msg('myfunction.name == ' + 
    myfunction.name);

var myfunctionexpr = function myfunction()
{
};

msg('myfunctionexpr.constructor.name ==' + 
    myfunctionexpr.constructor.name);
msg('myfunctionexpr.name == ' + 
    myfunctionexpr.name);

var anonfunction = new Function();

msg('anonfunction.constructor.name ==' + 
    anonfunction.constructor.name);
msg('anonfunction.name == ' + 
    anonfunction.name);

var anonfunctionexpr = function () {};

msg('anonfunctionexpr.constructor.name ==' + 
    anonfunctionexpr.constructor.name);
msg('anonfunctionexpr.name == ' + 
    anonfunctionexpr.name);


                            
Array Objects

Array objects are a special kind of JavaScript object which contain ordered lists of items. Array indexes are special zero-based integer valued properties of the Array object by which items can be retrieved using the member of [] operator. Array objects have a local property length which contains the number of items in the array. Unlike arrays in C, JavaScript Arrays, can grow or shrink in size and it is impossible to have a buffer overrun using JavaScript arrays. If array is an Array, and len

Arrays can be created either using array literal initializers of the form: var array = [item0, item1, …] or through the use of the Array constructor: var array = new Array().

Mozilla ignores empty element following trailing comma (,) in an array initializer. MSIE treats empty element following trailing comma (,) as an undefined element.

a=[,];
a.length == 1 in Mozilla
a.length == 2 in MSIE
var a = [,];
msg('a.length == ' + a.length);
for (var i = 0; i < a.length; i++)
{
  msg('a[' + i + '] == ' + a[i]);
}
Array(length)

Array can be called either as a constructor (new Array(len)) or as a function (Array(len)) to create a new instance of an Array with len items each initialized to undefined.

Mozilla JavaScript1.2 new Array(len) creates an array with one element consisting of the number len. Mozilla JavaScript1.1, JavaScript1.3 and later, MSIE will create an array of length len with undefined elements.

var array = new Array(100);
msg('array.length == ' + array.length);
msg('array[0] == ' + array[0]);
            

Array has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete Array
msg('Before delete: typeof Array == ' + typeof Array);
msg('(delete Array) == ' + (delete Array));
msg('After delete: typeof Array == ' + typeof Array);
// attempt to assign to Array
Array = 'foo';
msg('After Array = \'foo\': Array == ' + Array);
Array.prototype

Array.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

Array.prototype.constructor

Returns a reference to the Array constructor.

Array.prototype.toString()

Returns a string listing the string values of each element separated by , separator. The result is identical to the result returned by join(',')

Mozilla JavaScript1.2 will return a string representing an array literal initializer for the array instance. This is the same as the result of toString() with [ and ] surrounding the toString() value.

var array = [1, 2];

msg('array.toString() == ' + array.toString());
Array.prototype.toSource()

Mozilla will return a string representing an array literal initializer for the array instance. This is the same as the result of toString() with [ and ] surrounding the toString() value.

var array = [1, 2];

msg('array.toSource() == ' + array.toSource());
Array.prototype.toLocaleString()

Returns a localized string representing the Array.

Array.prototype.concat([item1[, item2 [, …]]])

Return a new array instance consisting of the elements of array item1, item2 in the same order.

var array1 = [1,2];
var array2 = [3,4];
var array3 = [5,6];
var result = array1.concat(array2,array3);

for (var i = 0; i < result.length; i++)
{
  msg('result[' + i + '] == ' + result[i]);
}
Array.prototype.join(separator)

Returns a string value consisting of the concatenation of the string values of each element separated by the separator.

MSIE will not default the separator to , if the separator value is undefined however it will if the separator is not specified.

var array = [1, 2];

msg('array.join() == ' + array.join());
msg('array.join(undefined) == ' + array.join(undefined));
msg('array.join(\'-\') == ' + array.join('-'));
Array.prototype.pop()

Removes the element at the end of the array and returns it as the value of the function call. If the array is empty, pop() returns undefined.

var stack = ['a', 'b', 'c'];

msg('stack.pop() == ' + stack.pop());
msg('stack.toString() == ' + stack.toString());

msg('stack.pop() == ' + stack.pop());
msg('stack.toString() == ' + stack.toString());

msg('stack.pop() == ' + stack.pop());
msg('stack.toString() == ' + stack.toString());

msg('stack.pop() == ' + stack.pop());
msg('stack.toString() == ' + stack.toString());
Array.prototype.push([item1[, item2[, …]]])

Inserts the item1, … at the end of the array and returns the new length of the array after the operation.

Mozilla JavaScript1.1, JavaScript1.2 return the pushed value rather than the new length of the array.

var stack = [];

msg('stack.push(\'a\') == ' + stack.push('a'));
msg('stack.toString() == ' + stack.toString());

msg('stack.push(\'b\') == ' + stack.push('b'));
msg('stack.toString() == ' + stack.toString());

msg('stack.push(\'c\') == ' + stack.push('c'));
msg('stack.toString() == ' + stack.toString());
Array.prototype.reverse()

Returns a copy of the Array instance with the items in reversed order

var array = [0, 1, 2, 3, 4];
msg('array.reverse() == ' + array.reverse());
Array.prototype.shift()

Removes the element at the 0th position in the array moving the remaining elements lower in the array and returns it as the value of the function call. If the array is empty, shift() returns undefined. See Array.prototype.pop().

var stack = ['a', 'b', 'c'];

msg('stack.shift() == ' + stack.shift());
msg('stack.toString() == ' + stack.toString());

msg('stack.shift() == ' + stack.shift());
msg('stack.toString() == ' + stack.toString());

msg('stack.shift() == ' + stack.shift());
msg('stack.toString() == ' + stack.toString());

msg('stack.shift() == ' + stack.shift());
msg('stack.toString() == ' + stack.toString());
Array.prototype.slice(start, end)

Returns an Array instance consisting of the items from the Array array from index start up to but not including end. If end is not specified or is undefined, it is treated as the length of the array. If start or end are negative, they are treated as array.length + start or array.length + end

var array = [0, 1, 2, 3, 4];
var length = array.length;

msg('array == ' + array);
msg('array.length == ' + length);

// return an array without the first item
msg('array.slice(1) == ' + array.slice(1));

// return an array consisting of the second and third items
msg('array.slice(1, 3) == ' + array.slice(1, 3));

// return an array consisting of the last item
msg('array.slice(-1, 5) == ' + array.slice(-1, 5));
msg('array.slice(length - 1, 5) == ' + array.slice(length - 1, 5));

// return an array without the first or last items
msg('array.slice(1, -1) == ' + array.slice(1, -1));
msg('array.slice(1, length - 1) == ' + array.slice(1, length - 1));

// return an array consisting of the third and fourth items
msg('array.slice(-3, -1) == ' + array.slice(-3, -1));
msg('array.slice(length - 3, length - 1) == ' + 
     array.slice(length - 3, length - 1));
Array.prototype.sort(comparefunc)

Returns an Array instance which has its items sorted according to the order defined by the comparison function comparefunc. comparefunc(left, right) determines the order by returning -1 if left should occur before right, +1 if left should occur after right or 0 if left and right have no preference as to order.

If comparefunc is not specified or is undefined, the default order specified by < used.

// output an array of Things sorted by name

// an object with a name
function Thing(name)
{
  this.name = name;
}

// allow Thing objects to be convertable to string values.
Thing.prototype.toString = function() { return this.name; };

// an array of Things
var array = [
             new Thing('Ralph'),
             new Thing('john'), 
             new Thing('george') 
            ];

function compareThings(left, right)
{
  // do case insenstive sort
  var lname = left.name.toLowerCase();
  var rname = right.name.toLowerCase();

  if (lname < rname)
    return -1;
  if (lname > rname)
    return +1;
  return 0;
}

msg('array.sort(compareThings) == ' + array.sort(compareThings));
Array.prototype.splice(start, deleteCount[, item1 [, item2[, …]]])

Replaces deleteCount elements from the array beginning at array index start with item1 …. Returns the removed elements as an array.

var array = [1, 2, 3, 4, 5];
var result = array.splice(0, 1, 'a');
msg('array.splice(0, 1, \'a\') == ' +
    result.toString() + 
    ' array.toString == ' + array.toString());

var array = [1, 2, 3, 4, 5];
result = array.splice(0, 2, 'b', 'c');
msg('array.splice(0, 2, \'b\', \'c\') == ' +
    result.toString() + 
    ' array.toString() == ' + array.toString());

Mozilla JavaScript1.2 will return a single removed element instead of an array containing the removed element.

Array.prototype.unshift([item1[, item2[, …]]])

Inserts the item1, … at the 0th … position in the array, shifting existing elements higher in the array and returns the new length of the array after the operation. See Array.prototype.push().

MSIE does not return the new length of the array, instead returning undefined.

var stack = [];

msg('stack.unshift(\'a\') == ' + stack.unshift('a'));
msg('stack.toString() == ' + stack.toString());

msg('stack.unshift(\'b\') == ' + stack.unshift('b'));
msg('stack.toString() == ' + stack.toString());

msg('stack.unshift(\'c\') == ' + stack.unshift('c'));
msg('stack.toString() == ' + stack.toString());
array.length

Returns the length (number of items) in the array. length has property attributes {DontEnum} and {DontDelete} which means it can not be enumerated in a for-in loop, or deleted by can be the target of an assignment. If the new value of length is less than the existing length of the array, the items past the new end of the array are deleted. If the new value of length is greater than the existing length of the array, the length of the array is increased and the new items are initialized to undefined.

var array = [0, 1, 2, 3, 4];
msg('array == ' + array);

// truncate array to length 2
array.length = 2;
msg('array == ' + array);

// increase array to length 6
array.length = 6;
msg('array == ' + array); 
String Objects
String

String has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete String
msg('Before delete: typeof String == ' + typeof String);
msg('(delete String) == ' + (delete String));
msg('After delete: typeof String == ' + typeof String);
// attempt to assign to String
String = 'foo';
msg('After String = \'foo\': String == ' + String);
String.prototype

String.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

String.prototype.constructor

Return a reference to the String constructor.

String.prototype.toString()

Returns the String converted to a string primitive value. (Same as String.prototype.valueOf)

msg('typeof (new String("foo")).toString() == ' + 
     typeof (new String("foo")).toString());
String.prototype.valueOf()

Return the String converted to a string primitive value. (Same as String.prototype.toString)

msg('typeof (new String("foo")).valueOf() == ' + 
     typeof (new String("foo")).valueOf());
String.prototype.charAt(pos)

Returns the character at index pos from the string.

var string = 'abcdefg';

msg('string.charAt(5) == ' + string.charAt(5));
Mozilla supports the alternate [] member of syntax to return characters from a string.
var string = 'abcdefg';

msg('string[5] == ' + string[5]);
String.prototype.charCodeAt(pos)

Returns a 16-bit number representing the Unicode code point value of the character at position pos in the string.

String.prototype.concat([string1[, string2[, …]]])

Converts its arguments to primitive string values, then returns a primitive string value consisting of the the characters from each of the arguments string1, string2, … in the same order.

String.prototype.concat and operator + are equivalent on string operands.

Example Concat a primitive string, instance of String Object and an instance of Array Object

var s1 = '123';
var s2 = new String('456');
var s3 = ['789'];
var result = s1.concat(s2, s3);

msg('result = s1.concat(s2, s3)');
msg('result == ' + result);
msg('typeof result == ' + typeof result);

Example Concat a primitive string, instance of String Object and an instance of Array Object using the string + operator.

var s1 = '123';
var s2 = new String('456');
var s3 = ['789'];
var result = s1.concat(s2, s3);

msg('result = s1 + s2 + s3');
msg('result == ' + result);
msg('typeof result == ' + typeof result);
String.prototype.indexOf(searchString, position)

Converts the this value and the searchString argument to primitive string values and position to a number value, then searches the this string value beginning at position, returning the position in the string where searchString appears or -1 if it is not found. If position is undefined, searching begins at position 0.

// get the first occurrence of 'Bar'
var string = 'FooBarfoobarFooBarBaz';
var result = string.indexOf('Bar');

msg("string = 'FooBarfoobarFooBarBaz'");
msg("result = string.indexOf('Bar');");
msg('result  == ' + result);

// get the next occurrence of 'Bar'
result = string.indexOf('Bar', result + 'Bar'.length);
msg("result = string.indexOf('Bar', result + 'Bar'.length');");
msg('result  == ' + result);
String.prototype.lastIndexOf(searchString, position)

Converts the this value and the searchString argument to primitive string values and position to a number value, then searches the this string value backwards beginning at position, returning the position in the string where searchString appears or -1 if it is not found. If position is undefined, searching begins at the last position in the string.

// get the last occurrence of 'Bar'
var string = 'FooBarfoobarFooBarBaz';
var result = string.lastIndexOf('Bar');

msg("string = 'FooBarfoobarFooBarBaz'");
msg("result = string.lastIndexOf('Bar');");
msg('result  == ' + result);

// get the next to last occurrence of 'Bar'
result = string.lastIndexOf('Bar', result - 1);
msg("result = string.lastIndexOf('Bar', result - 1);");
msg('result  == ' + result);
String.prototype.localeCompare(that)

Converts the this value and the that argument to primitive string values, then returns a number representing how this compares to that in the current locale:

-1
this compares less than that
+1
this compares greater than that
0
this and that compare as equal
String.prototype.match(regexp)

Converts this to a primitive string value, and if regexp is not an instance of RegExp converts it to a regular expression via new RegExp(regexp), then returns an array containing the matches. The actual result array depends upon whether the regular expression is global or not.

If regexp is a non global regular expression, then the result array is the same as returned by RegExp.prototype.exec

.

In this example using a non global regular expression, match will return an array instance whose first element is the substring which was matched ('aa' in this case) and whose second element contains the part of the string which matched the capturing parentheses ('aa') in this case).

var string = 'aabbbccccdddd';
var regexp = /(a*)/;
var result = string.match(regexp);
msg('result == ' + result);
msg('result.length == ' + result.length);

// compare to the result of calling RegExp.prototype.exec
msg('regexp.exec(string) == ' + regexp.exec(string));

If regexp is a global regular expression (has the g flag), then regexp.lastIndex is set to 0, then RegExp.prototype.exec is repeatedly called until there are no more matches each time updating regexp.lastIndex. The result array is constructed from the matched substrings of each of the exec calls. If any of the calls to exec match the empty string '', then lastIndex is incremented to start the next search at the next character in the string.

XXX: Compatibility issues described in Bug 225094"

In this example using a global regular expression, match will return an array whose first element is the substring which was first matched ('aa' in this case). The remainder of the result array contains the subsequent matches where (a*) was matched to the empty string at each position.

var string = 'aabbbccccdddd';
var regexp = /(a*)/g;
var result = string.match(regexp);
msg('test String.prototype.match');
msg('result == ' + result);
msg('result.length == ' + result.length);

// compare to the result of repeatedly calling
//  RegExp.prototype.exec on the regular expression
regexp.lastIndex = 0;
result = [];
var temp;
while (regexp.lastIndex <= string.length)
{
  temp = regexp.exec(string);
  result[result.length] = temp[0];
 if (!temp[0])
  {
    regexp.lastIndex++;
  }
}
msg('test repeated calls to RegExp.prototype.exec');
msg('result == ' + result);
msg('result.length == ' + result.length);
String.prototype.replace(searchValue, replaceValue)

In its simplest form, replace replaces the first occurence of the string searchValue with the string replaceValue.

var string = 'The situation is all fubar which is fundamental.';
var result = string.replace('fu', 'foo');
msg('result == ' + result);

Mozilla JavaScript 1.1, 1.2, 1.3, 1.4 will attempt to convert the first argument to String.prototype.replace to a regular expression. If the first argument is a string which does not contain a valid regular expression, an error will be thrown.

In Mozilla JavaScript 1.5, if the first argument is a string, no conversion is attempted and no error is thrown.

bug 280546

try
{
  msg("f?oo".replace('?oo','ee'));
}
catch(e)
{
  msg(e.name + ': ' + e.message);
}

When searchValue is a regular expression, replaces the match in the string by replaceValue. If the regular expression has its global property set, replace will replace all matches.

The following special strings can be used in the replaceValue string which will be replaced as follows:

Characters Result
$$ $
$& the matched substring
$` the portion of string preceding the match
$' the portion of the string following the match
$n the nth element from the capture array where n is a single digit 1-9.
$$ the nnth element from the capture array where nn is a 2 digit number 01-99
var string = 'The situation is all fubar which is fundamental.';
var result = string.replace(/fu/g, 'foo');
msg('result == ' + result);

result = string.replace(/fu/g, "(match=$&, prefix=$`, suffix=$')");
msg('result == ' + result);

When searchValue is a string and replaceValue is a function, then for each match of searchValue, the function is called with the first argument containing the matched string, the second argument containing the offset of the match in the string followed by the value of the string itself.


var string = 'The situation is all fubar which is fundamental.';
var result = string.replace('fu', myreplace);
msg('result == ' + result);

function myreplace(string)
{
  msg('myreplace: arguments.length == ' + arguments.length);
  for (var i = 0; i < arguments.length; i++) 
  {
    msg('arguments[' + i + '] == ' + arguments[i]);
  }  
  return ' myreplace-foo-myreplace ';
}

When searchValue is a regular expression and replaceValue is a function, then for each match of searchValue, the function is called with the first argument containing the matched string, and the remaining arguments are the elements of the match array, followed by the offset in the string where the match occured, and the final argument is the value of the string itself.


var string = 'The situation is all fubar which is fundamental.';
var result = string.replace(/((f)(u))/g, myreplace);
msg('result == ' + result);

function myreplace(string)
{
  msg('myreplace: arguments.length == ' + arguments.length);
  for (var i = 0; i < arguments.length; i++) 
  {
    msg('arguments[' + i + '] == ' + arguments[i]);
  }  
  return ' myreplace-foo-myreplace ';
}
String.prototype.search(regexp)

Converts the this value to a primitive string and if regexp is not an instance of RegExp, converts it to a regular expression via new RegExp(regexp), then returns the position in the this value which first matches regexp or -1 is no match is found.

// search 'FooBar' for a letter
var string = 'FooBar';
var regexp = /[a-zA-Z]/;
var result = string.search(regexp);
msg('A letter occurs in ' + string + ' at position ' + result);

// search 'FooBar' for a number
regexp = /[0-9]/;
result = string.search(regexp);
msg('A number occurs in ' + string + ' at position ' + result);
String.prototype.slice(start,end)

Converts the this value to a primitive string and the arguments start, end to integers, then returns a string value consisting of the characters in the this value from position start up to but not including position end. If end is undefined, then end is treated as the length of the this string.

If start or end are less than zero, they are treated as this.length + start and this.length + end respectively.

var string = '01234';
var length = string.length;

msg('string == ' + string);
msg('string.length == ' + length);

// return an string without the first item
msg('string.slice(1) == ' + string.slice(1));

// return an string consisting of the second and third items
msg('string.slice(1, 3) == ' + string.slice(1, 3));

// return an string consisting of the last item
msg('string.slice(-1, 5) == ' + string.slice(-1, 5));
msg('string.slice(length - 1, 5) == ' + string.slice(length - 1, 5));

// return an string without the first or last items
msg('string.slice(1, -1) == ' + string.slice(1, -1));
msg('string.slice(1, length - 1) == ' + string.slice(1, length - 1));

// return an string consisting of the third and fourth items
msg('string.slice(-3, -1) == ' + string.slice(-3, -1));
msg('string.slice(length - 3, length - 1) == ' + 
     string.slice(length - 3, length - 1));
String.prototype.split(separator,limit)

Returns an array of length at most limit consisting of elements containing the substrings of the this input string which were separated by separator. separator can be either a string or regular expression. Note that an empty string "" can be returned as the prefix of the separator at the beginning of the this input string or as a suffix of the separator at the end of the this input string.

If separator is an empty string, an empty regular expression or a regular expression matching an empty string, the returned array consists of an element for each character in the this input string.

// empty string as separator
msg('"ab".split("") == ' + "ab".split(""));

// empty regular expression as separator
msg('"ab".split(/(?:/)) == ' + "ab".split(/(?:)/));

Mozilla JavaScript1.2 emulates Perl4 when the separator is a single space it will skip leading whitespace and splits on whitespace instead of on each space character.

var string = "   123   456   ";
msg('string.split(" ").join() == ' + 
    string.split(" ").join());

If separator is a regular expression, only the first match is considered.

For example, "ab".split(/a*/) uses a greedy match for a maximum length match for zero or more a characters, therefore the first match consists of the a which results in the empty string "" as its prefix and the b as the remainder of the string. Thus the return value would be ["","b"] The empty string result is not rejected even though another possible match could have been the leading empty string matching zero a characters.

By contrast "ab".split(/a*?/) uses a non-greedy match for the minimum length match for zero or more characters, therefore the first match consists of the empty string "" at the beginning of the string. The second match is the zero length string separating the a and b characters resulting in a return value of ["a","b"].

msg('"ab".split(/a*/) == ' + "ab".split(/a*/));

msg('"ab".split(/a*?/) == ' + "ab".split(/a*?/));

If the this input string is empty, and the separator matches the empty string, then there are no substrings and the result is the empty array.

If the this input string is empty and the separator does not match the empty string, then the result is an array of one element consisting of the empty string.

msg('"".split(""/).length == ' + "".split("").length);

msg('"".split(/a/).length == ' + "".split(/a/).length);

If separator is a reqular expression containing capturing parentheses, then the results of the capturing parentheses (including undefined are spliced into the resulting array.


var string = "A<B>bold</B>and<CODE>coded</CODE>";
var regexp = /<(\/)?([^<>]+)>/;
var result = string.split(regexp);

for (var i = 0; i < result.length; i++)
{
  msg('typeof result[' + i + '] == ' + typeof result[i] + ', ' +
      'result[' + i + '] == ' + result[i]); 
}

Note that neither Mozilla nor MSIE reproduce the output listed in the ECMA 262 3rd edition. Mozilla outputs empty strings instead of undefined and MSIE fails to output the elements of the capturing array, instead ignoring the capturing parentheses altogether.

ECMA 262 3rd
["A",  undefined, "B",    "bold",  "/", "B", 
"and", undefined, "CODE", "coded", "/", "CODE", 
""]
Mozilla
["A",  "",        "B",    "bold",  "/", "B",
"and", "",        "CODE", "coded", "/", "CODE", 
""]
MSIE
["A", "bold", "and", "coded"]

Trying the previous example with non-capturing parentheses shows that MSIE definitely ignores capturing parentheses in split regular expressions. Note that Mozilla has one extra empty string element at the end of the array.


var string = "A<B>bold</B>and<CODE>coded</CODE>";
var regexp = /<(?:\/)?(?:[^<>]+)>/;
var result = string.split(regexp);

for (var i = 0; i < result.length; i++)
{
  msg('typeof result[' + i + '] == ' + typeof result[i] + ', ' +
      'result[' + i + '] == ' + result[i]); 
}

Finally, if separator is undefined, the result is an array with one element consisting of the this string value.

var string = "regular expressions are foonderbar";

// separator is not passed to split
var result = string.split();

for (var i = 0; i < result.length; i++)
{
  msg('typeof result[' + i + '] == ' + typeof result[i] + ', ' +
      'result[' + i + '] == ' + result[i]); 
}

// separator is specified to be undefined
var result = string.split(undefined);

for (var i = 0; i < result.length; i++)
{
  msg('typeof result[' + i + '] == ' + typeof result[i] + ', ' +
      'result[' + i + '] == ' + result[i]); 
}
String.prototype.substring(start, end)

Returns a string value (not Object) consisting of the characters in the this string value from index position start up to but not including end. If end is not specified or is undefined, end is treated as the length of the string value.

If start > end, they are swapped.

If start is greater than or equal to the this string length, the null string is returned.

Mozilla JavaScript1.2, will not swap the arguments start, end if start > end however Mozilla JavaScript1.3 and later will.

var string = "abcdef";
msg('string.substring(1,2) == ' + string.substring(1,2));
msg('string.substring(1)   == ' + string.substring(1));
msg('string.substring(2,1) == ' + string.substring(2,1));
msg('string.substring(200) == ' + string.substring(200));
String.prototype.substr(start, length)

Not standard but available in Mozilla and MSIE.

Returns a string value (not Object) of length length consisting of the characters in the this string value from index position start. If start + length > this.toString().length, or if length is not specified the remainder of the this string is returned.

If start is greater than or equal to the this string length, the null string is returned.

var string = "abcdef";
msg('string.substr(1,2) == ' + string.substr(1,2));
msg('string.substr(1)   == ' + string.substr(1));
msg('string.substr(2,1) == ' + string.substr(2,1));
msg('string.substr(200) == ' + string.substr(200));
String.prototype.toLowerCase()

Returns a string value consisting of the original this string value with all upper case characters converted to lower case.

var s = 'This is a String.';
msg('s.toLowerCase() == ' + s.toLowerCase());
String.prototype.toLocaleLowerCase()

Returns a string value consisting of the original this string value with all upper case upper characters converted to lowercase using a locale specific mapping of upper to lower case characters.

var s = 'This is a String.';
msg('s.toLocaleLowerCase() == ' + s.toLocaleLowerCase());
String.prototype.toUpperCase()

Returns a string value consisting of the original this string value with all lower case characters converted to upper case.

var s = 'This is a String.';
msg('s.toUpperCase() == ' + s.toUpperCase());
String.prototype.toLocaleUpperCase()

Returns a string value consisting of the original this string value with all lower case characters converted to upper case using a locale specific mapping of upper to lower case characters.

var s = 'This is a String.';
msg('s.toLocaleUpperCase() == ' + s.toLocaleUpperCase());
String.fromCharCode([char0[, char1[, …]]])

Converts its arguments to 16-bit integers, then returns a string which consists of the characters with those values as their Unicode code point values.

var result = '';
for (var charCode = 32; charCode < 256; charCode++)
{
  result += String.fromCharCode(charCode);
}
msg('result == ' + result);
string.length

length is a local property of String instances which returns the number of characters in the string. string.length has property attributes {DontEnum}, {DontDelete} and {ReadOnly}.

// attempt to delete string.length
var string = '01234';
msg('Before delete: typeof string.length == ' + typeof string.length);
msg('(delete string.length) == ' + (delete string.length));
msg('After delete: typeof string.length == ' + typeof string.length);
// attempt to assign to string.length
var string = '01234';
string.length = 2;
msg('After string.length = 2: string.length == ' + string.length);
Boolean Objects

Boolean objects are objects which represent boolean (true and false) values but are not the same as the primitive values true and false. The fact that any instance of Boolean evaluates to true when used in conditional expressions, means that care must be taken when using instances of Boolean in conditional expressions.

Boolean(value)

When called as a constructor (new Boolean(value) creates an instance of a Boolean object with value value. When called as a function, Boolean(value) converts value to a Boolean Object.

Boolean has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete Boolean
msg('Before delete: typeof Boolean == ' + typeof Boolean);
msg('(delete Boolean) == ' + (delete Boolean));
msg('After delete: typeof Boolean == ' + typeof Boolean);
// attempt to assign to Boolean
Boolean = 'foo';
msg('After Boolean = \'foo\': Boolean == ' + Boolean);
Boolean.prototype

Boolean.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

Boolean.protototype.constructor

Returns a references to the Boolean constructor.

Boolean.protototype.toString()

Returns the value of the Boolean object converted to a string.

msg('typeof (new Boolean(true)).toString() == ' + 
     typeof (new Boolean(true)).toString());

msg('(new Boolean(true)).toString() == ' + 
      (new Boolean(true)).toString());

msg('typeof (new Boolean(false)).toString() == ' + 
     typeof (new Boolean(false)));

msg('(new Boolean(false)).toString() == ' + 
      (new Boolean(false)).toString());
Boolean.protototype.valueOf()

Returns the primitive boolean value of the Boolean instance.

msg('typeof (new Boolean(false)).valueOf() == ' + 
     typeof (new Boolean(false)).valueOf());

msg('(new Boolean(true)).valueOf() == ' + 
      (new Boolean(true)).valueOf());

msg('typeof (new Boolean(false)).valueOf() == ' + 
     typeof (new Boolean(false)).valueOf());

msg('(new Boolean(false)).valueOf() == ' + 
     (new Boolean(false)).valueOf());
Number Objects
Number(value)

When called as a constructor (new Number(value)) creates an instance of a Number object with value value. When called as a function, Number(value) converts value to a Number Object.

Number has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete Number
msg('Before delete: typeof Number == ' + typeof Number);
msg('(delete Number) == ' + (delete Number));
msg('After delete: typeof Number == ' + typeof Number);
// attempt to assign to Number
Number = 'foo';
msg('After Number = \'foo\': Number == ' + Number);
Number.prototype

Number.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

Number.prototype.constructor

Returns a reference to the Number constructor.

Number.prototype.toString(radix)

Returns a string value representing the value of the Number object in base radix. If radix is either 10 or undefined, the result is the number in base 10 notation. Otherwise, if radix is a number from 2 to 36, the resulting string is an implementation dependent representation of the number in base radix.

var theanswer = 42;
msg('theanswer.toString() == ' + theanswer.toString());
msg('theanswer.toString(2) == ' + theanswer.toString(2));
msg('theanswer.toString(8) == ' + theanswer.toString(8));
msg('theanswer.toString(16) == ' + theanswer.toString(16));
msg('theanswer.toString(36) == ' + theanswer.toString(36));

// try an invalid radix
try
{
  msg('theanswer.toString(100) == ' + theanswer.toString(100));
}
catch(e)
{
  msg('Invalid Radix Error: ' + e.name + ': ' + e.message);
}

When an invalid radix value is used, Mozilla will throw a generic Error object with message illegal radix value while MSIE will throw a TypeError object with message Invalid procedure call or argument.

Number.prototype.toLocaleString()

Returns a locale specific string representation of the number value in base 10.

Number.prototype.valueOf()

Returns the this value for the Number instance converted to a primitive number value.

var number = new Number(42);
msg('typeof (new Number(42)).valueOf() == ' + 
     typeof (new Number(42)).valueOf());
msg('(new Number(42)).valueOf() == ' + 
     (new Number(42)).valueOf());
Number.prototype.toFixed(fractionDigits)

Returns a string value representing the number value with fractionDigits places after the decimal point. If fractionDigits is undefined, then 0 is used.

Mozilla does not throw a RangeError if fractionDigits is greater than 20 or less than 0. MSIE throws a RangeError in both cases. Mozilla's behavior is allowed under ECMAScript 15.7.4.5 Number.prototype.toFixed(fractionDigits).

var number = 123.456;
msg('number.toFixed(2) == ' + number.toFixed(2));

// check for RangeError for fractionDigits > 20
try
{
  msg('number.toFixed(21) == ' + number.toFixed(21));
  msg('Test failed. Should have thrown a RangeError.');
}
catch(e)
{
  msg('Expected Exception thrown. ' +  
      e.name + ': ' + e.message);
  try
  {
    msg('Exception is a RangeError: ' + (e instanceof RangeError));
  }
  catch(e2)
  {
    msg('Error using instanceof ' +  
      e2.name + ': ' + e2.message);
  }
}

// check for RangeError for fractionDigits < 0
try
{
  msg('number.toFixed(-1) == ' + number.toFixed(-1));
  msg('Test failed. Should have thrown a RangeError.');
}
catch(e)
{
  msg('Expected Exception thrown. ' +  
      e.name + ': ' + e.message);
  try
  {
    msg('Exception is a RangeError: ' + (e instanceof RangeError));
  }
  catch(e2)
  {
    msg('Error using instanceof ' +  
      e2.name + ': ' + e2.message);
  }
}
Number.prototype.toExponentional(fractionDigits)

Returns a string value representing the number value in exponential form with one digit before the decimal point and with fractionDigits places after the decimal point. If fractionDigits is undefined, then as many digits after the decimal as are required to specify the number uniquely are used.

Mozilla does not throw a RangeError if fractionDigits is greater than 20 but does if it is less than 0. MSIE throws a RangeError in both cases. Mozilla's behavior is allowed under ECMAScript 15.7.4.6 Number.prototype.toFixed(fractionDigits).

var number = 123.456;
msg('number.toExponential(2) == ' + number.toExponential(2));

// check for RangeError for fractionDigits > 20
try
{
  msg('number.toExponential(21) == ' + number.toExponential(21));
  msg('Test failed. Should have thrown a RangeError.');
}
catch(e)
{
  msg('Expected Exception thrown. ' +  
      e.name + ': ' + e.message);
  try
  {
    msg('Exception is a RangeError: ' + (e instanceof RangeError));
  }
  catch(e2)
  {
    msg('Error using instanceof ' +  
      e2.name + ': ' + e2.message);
  }
}

// check for RangeError for fractionDigits < 0
try
{
  msg('number.toExponential(-1) == ' + number.toExponential(-1));
  msg('Test failed. Should have thrown a RangeError.');
}
catch(e)
{
  msg('Expected Exception thrown. ' +  
      e.name + ': ' + e.message);
  try
  {
    msg('Exception is a RangeError: ' + (e instanceof RangeError));
  }
  catch(e2)
  {
    msg('Error using instanceof ' +  
      e2.name + ': ' + e2.message);
  }
}
Number.prototype.toPrecision(precision)

Returns a string value representing the number value using precision number of significant digits. If precision is undefined, Number.prototype.toString() is used to return the string value.

Mozilla does not throw a RangeError if fractionDigits is greater than 21 but does if it is than 1. MSIE throws a RangeError in both cases. Mozilla's behavior is allowed under ECMAScript 15.7.4.7 Number.prototype.toPrecision(fractionDigits).

var number = 123.456;
msg('number.toPrecision(2) == ' + number.toPrecision(2));

// check for RangeError for fractionDigits > 21
try
{
  msg('number.toPrecision(22) == ' + number.toPrecision(22));
  msg('Test failed. Should have thrown a RangeError.');
}
catch(e)
{
  msg('Expected Exception thrown. ' +  
      e.name + ': ' + e.message);
  try
  {
    msg('Exception is a RangeError: ' + (e instanceof RangeError));
  }
  catch(e2)
  {
    msg('Error using instanceof ' +  
      e2.name + ': ' + e2.message);
  }
}

// check for RangeError for fractionDigits < 1
try
{
  msg('number.toPrecision(0) == ' + number.toPrecision(0));
  msg('Test failed. Should have thrown a RangeError.');
}
catch(e)
{
  msg('Expected Exception thrown. ' +  
      e.name + ': ' + e.message);
  try
  {
    msg('Exception is a RangeError: ' + (e instanceof RangeError));
  }
  catch(e2)
  {
    msg('Error using instanceof ' +  
      e2.name + ': ' + e2.message);
  }
}
Number.MAX_VALUE

Returns the maximum value of a number representable in JavaScript.

msg('Number.MAX_VALUE == ' + Number.MAX_VALUE);
Number.MIN_VALUE

Returns the minimum value of a number representable in JavaScript.

msg('Number.MIN_VALUE == ' + Number.MIN_VALUE);
Number.NaN

Returns the same value as the global property NaN.

Number.NEGATIVE_INFINITY

Returns -Infinity

msg('Number.NEGATIVE_INFINITY == ' + Number.NEGATIVE_INFINITY);
Number.POSITIVE_INFINITY

Returns +Infinity

msg('Number.POSITIVE_INFINITY == ' + Number.POSITIVE_INFINITY);
The Math Object

The Math object which, unlike the other JavaScript objects, is a static object which can not be used as a constructor or as a function. It is used to contain a number of numeric constants which otherwise would require computation as well as a number of functions which perform common mathematics operations. All of the numeric constants have property attributes {DontEnum}, {DontDelete} and {ReadOnly}.

Math.E

The value for the number e which is the base of the natural logarithms.

msg('Math.E == ' + Math.E);
msg('Math.log(Math.E) == 1 ' + (Math.log(Math.E) == 1))
msg('Math.E == Math.exp(1) ' + (Math.E == Math.exp(1)));
Math.LN10

The value for the natural logarithm of 10.

msg('Math.LN10 == ' + Math.LN10);
msg('1/Math.LOG10E == ' + 1/Math.LOG10E);
msg('Math.LN10 == 1/Math.LOG10E ' + (Math.LN10 == 1/Math.LOG10E));
Math.LN2

The value for the natural logarithm of 2.

msg('Math.LN2 == ' + Math.LN2);
msg('Math.exp(Math.LN2) == ' + Math.exp(Math.LN2));
msg('Math.exp(Math.LN2) == 2 ' + (Math.exp(Math.LN2) == 2));
Math.LOG2E

The value for the base 2 logarithm of e.

msg('Math.LOG2E == ' + Math.LOG2E);
msg('1/Math.LN2 == ' + 1/Math.LN2);
msg('Math.LOG2E == 1/Math.LN2 ' + (Math.LOG2E == 1/Math.LN2));
Math.LOG10E

The value for the base 10 logarithm of e.

msg('Math.LOG10E == ' + Math.LOG10E);
msg('1/Math.LN10 == ' + 1/Math.LN10);
msg('Math.LOG10E == 1/Math.LN10 ' + (Math.LOG10E == 1/Math.LN10));
Math.PI

The value for Π.

msg('Math.PI == ' + Math.PI);
Math.SQRT1_2

The value for the square root of ½.

msg('Math.SQRT1_2 == ' + Math.SQRT1_2);
msg('1/Math.SQRT2 == ' + 1/Math.SQRT2);
msg('Math.SQRT1_2 == 1/Math.SQRT2 ' + (Math.SQRT1_2 == 1/Math.SQRT2));
Math.SQRT2

The value for the square root of 2.

msg('Math.SQRT2 == ' + Math.SQRT2);
msg('Math.SQRT2 * Math.SQRT2 == ' + (Math.SQRT2 * Math.SQRT2));
msg('Math.SQRT2 * Math.SQRT2 == 2 ' + (Math.SQRT2 * Math.SQRT2 == 2));
Math.abs(x)

Returns the absolute value of x.

msg('Math.abs(-1) == ' + Math.abs(-1));
Math.acos(x)

Returns the arc cosine (cos-1) of x

msg('Math.acos(Math.cos(Math.PI))) == ' + Math.acos(Math.cos(Math.PI)));
Math.asin(x)

Returns the arc sine (sin-1) of x

msg('Math.asin(Math.sin(Math.PI))) == ' + Math.asin(Math.sin(Math.PI)));
Math.atan(x)

Returns the arc tangent (tan-1) of x

msg('Math.atan(Math.tan(Math.PI/2))) == ' + Math.atan(Math.tan(Math.PI/2)));
Math.atan2(y,x)

Returns the arc tangent (tan-1) of the ratio of y/x with the return value in the property quadrant.

msg('Math.atan2(1,-1) == ' + Math.atan2(1,-1));
Math.ceil(x)

Returns the smallest integer value less than or equal to x.

msg('Math.ceil(NaN) == ' + Math.ceil(NaN));
msg('Math.ceil(+0) == '  + Math.ceil(+0));
msg('Math.ceil(-0) == '  + Math.ceil(-0));
msg('Math.ceil(+Infinity) == ' + Math.ceil(+Infinity));
msg('Math.ceil(-Infinity) == ' + Math.ceil(-Infinity));
msg('Math.ceil(-0.5) == ' + Math.ceil(-0.5));
msg('Math.ceil(1.6) == ' + Math.ceil(1.6));

msg('-Math.floor(-1.6) == ' + (-Math.floor(-1.6)));
Math.cos(x)

Converts x to a numeric value in radians and returns the cosine of x.

msg('Math.cos(Math.PI) == ' + Math.cos(Math.PI));
Math.exp(x)

Converts x to a numeric value, then returns the result of raising e to the xth power (ex).

Math.floor(x)

Returns the largest integer value less than or equal to the numeric value of x.

msg('Math.floor(NaN) == ' + Math.floor(NaN));
msg('Math.floor(+0) == '  + Math.floor(+0));
msg('Math.floor(-0) == '  + Math.floor(-0));
msg('Math.floor(+Infinity) == ' + Math.floor(+Infinity));
msg('Math.floor(-Infinity) == ' + Math.floor(-Infinity));
msg('Math.floor(-0.5) == ' + Math.floor(-0.5));
msg('Math.floor(1.6) == ' + Math.floor(1.6));

msg('-Math.floor(-1.6) == ' + (-Math. ceil(-1.6)));
Math.log(x)

Converts x to a numeric value, then returns the natural logarithm of x.

Math.max([value1 [, value2 [, …]]])

Converts each argument value1, value2, … to a numeric value, then returns the maximum value.

Math.min([value1 [, value2 [, …]]])
Converts each argument value1, value2, … to a numeric value, then returns the minimum value.
Math.pow(x,y)

Converts x and y to numeric values, then returns the value raising x to the yth power (yx).

Math.random()

Returns a random number between 0 and 1.

Math.round(x)

Converts x to a numeric value and returns the result of rounding x to the nearest integer.

Math.sin(x)

Converts x to a numeric value in radians and returns the sine of x.

Math.sqrt(x)

Converts x to a numeric value and returns the square root of x.

Math.tan(x)

Converts x to a numeric value in radians and returns the tangent of x.

Date Objects

Instances of the Date Object represent time values to within a millisecond for dates 100,000 days before or after January 1, 1970. Time 0 is defined to be January 1, 1970 UTC. This works out to be from April 20, -271821 through September 13, 275760 which should be enough for most purposes.

Date(…)

The Date constructor creates a new instance of a Date Object when called in a new expression but returns a string when used as a function call when it returns the same value a (new Date()).toString().

Date has two forms: Date(value) and Date(year, month, …).

Date has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete Date
msg('Before delete: typeof Date == ' + typeof Date);
msg('(delete Date) == ' + (delete Date));
msg('After delete: typeof Date == ' + typeof Date);
// attempt to assign to Date
Date = 'foo';
msg('After Date = \'foo\': Date == ' + Date);
Date(value)

Date(value) creates a new instance of Date by parsing value as a date string in IETF format or as the number of milliseconds since January 1, 1970.

Example Date Ranges using Date(milliseconds )

var msDay = 86400000; // milliseconds per day
var maxRange = 100000000 * msDay;

var datemin = new Date(-maxRange);
var date0 = new Date(0);
var datemax = new Date(maxRange);

msg('datemin == ' + datemin.toUTCString());
msg('date0 == ' + date0.toUTCString());
msg('datemax == ' + datemax.toUTCString());

try
{
  // try a longer range
  var date = new Date(maxRange + 1);
  msg('date == ' + date.toUTCString());
}
catch(e)
{
  msg(e.name + ': ' + e.message);
}

Note that Mozilla will report 'Invalid Date' for dates out of range while MSIE will report 'NaN'.

The IETF date format is defined in RFC 822, Section 5. JavaScript is more lenient in the date strings it will accept in that some of the required values in RFC 822 can be omitted in JavaScript and other values can be written in abbreviated form or in full. In general JavaScript date strings look like:

[dayofweek] dayofmonth month year [time [timezone][offset]]

where commas (,) in between the values will be ignored and [optional] indicates optional can be omitted.

dayofweek is the name of the day of the week such as Monday or Mon; dayofmonth is a number representing the day of the month ranging from 1 to the number of days in the month, month is the name of the month such as January or Jan; year is a number representing the year; time is of the form hh:mm or hh:mm:ss (where hh, mm and ss are two digit numbers representing the hours, minutes and seconds); and timezone is optionally one of UTC, GMT, EST, EDT, CST, CDT, MST, MDT, PST, PDT; and offset is a positive or negative 4 digit number representing the difference in time between the local time and that given in the timezone.

JavaScript will convert some invalid dates with an incorrect dayofmonth value by shifting the date into the next month.

function test(datestring)
{
  msg('new Date("' + datestring + '") == ' + 
      new Date(datestring));
}

// create Date using date string
var datestring;

msg('Valid Dates');

test("Jan 12 2005 11:57 PM EST");
test("January 12 2005");
test("01/12/2005");
test("Wed January 12, 2005");
test("12, Jan, 2005, 11:57, PM, EST");
test("Wed Jan 12 2005 23:57:00 GMT-0500 (Eastern Standard Time)");

msg('Invalid dates');

test("01 2005");
test("01 12 2005");
test("Feb 31, 2005");
test("Jan 12, 2005 13:30 AM");

Note that both Mozilla and MSIE will flag "01 12 2005" as an invalid date and that both will convert "Feb 31, 2005" to "Mar 3, 2005", but they disagree when a 24 hour time is used with an AM or PM indicator. Mozilla flags a 24 hour time with AM or PM as an invalid date while MSIE ignores the AM/PM indicator.

Care must be taken to generate only valid date strings in order for your code to be interoperable between browsers.

Date([year[, month[, date[, hours[, minutes[, seconds[, ms]]]]]]]) (Function Call)

All arguments are optional and are ignored. The result of calling the Date constructor is always the same as (new Date()).toString() regardless of the arguments passed.

Calling Date as a function should always return the current date as a string.

msg('Date(1970, 01, 01) == ' + Date(1970, 01, 01));
Date(year, month[, day[, hours[, minutes[, seconds[, ms]]]]]) (Constructor Call)

Constructs an instance of Date corresponding to the date specified in the arguments. Each argument is first converted to a Number. If the value is greater than the allowed value (e.g. if month is greater than 11, hour is greater than 23, etc.) then the excess is carried into the previous value and the value is treated as modulo the maximum value. For example if month is greater than 11, year is treated as year + floor(month/12) and month as month % 12.

year
If year is in the range 0 to 99, it is treated as year + 99 otherwise is it treated as the full year of the date.
month
The number of the month from 0 (January) to 11 (December).
day
The number of the day in the month from 1 to the number of days in the month
hours
The number of hours from 0 to 23.
minutes
The number of minutes from 0 to 59.
seconds
The number of seconds from 0 to 59.
ms
The number of milliseconds from 0 to 999.
msg(' two digit year');
msg('new Date(0, 0) == ' + new Date(0, 0));

msg('year, month')
msg('new Date(2000, 11) == ' + 
    new Date(2000, 11));

msg('year, month with carry');
msg('new Date(2000, 12) == ' + 
     new Date(2000, 12));

msg('year, month, day');
msg('new Date(2000, 11, 7) == ' + 
    (new Date(2000, 11, 7)));

msg('year, month, day with carry');
msg('new Date(2000, 11, 32) == ' + 
    (new Date(2000, 11, 32)));

msg('year, month, day, hours');
msg('new Date(2000, 11, 7, 23) == ' + 
    (new Date(2000, 11, 7, 23)));

msg('year, month, day, hours with carry');
msg('new Date(2000, 11, 7, 24) == ' + 
    (new Date(2000, 11, 7, 24)));

msg('year, month, day, hours, seconds');
msg('new Date(2000, 11, 7, 23, 59) == ' + 
    (new Date(2000, 11, 7, 23, 59)));

msg('year, month, day, hours, seconds with carry');
msg('new Date(2000, 11, 7, 23, 60) == ' + 
    (new Date(2000, 11, 7, 23, 60)));

msg('year, month, day, hours, seconds, ms');
msg('new Date(2000, 11, 7, 23, 59) == ' + 
    (new Date(2000, 11, 7, 23, 59, 999)));

msg('year, month, day, hours, seconds, ms with carry');
msg('new Date(2000, 11, 7, 23, 59, 1000) == ' + 
    (new Date(2000, 11, 7, 23, 59, 1000)));

Date.prototype

Date.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

Date.prototype.constructor

Returns a reference to the Date constructor.

Date.prototype.toString()

Returns a string representing the date, time value.

Mozilla and MSIE differ in how date/time format string.

Mozilla
Thu Jul 04 1776 12:30:00 GMT-0500 (Eastern Standard Time)
MSIE
Thu Jul 4 12:30:00 EDT 1776
var date = new Date('7/4/1776 12:30 PM');
msg('date.toString() == ' + date.toString());
Date.prototype.toDateString()

Returns a string representing only the date.

Mozilla and MSIE agreed on Date string format.

var date = new Date('7/4/1776 12:30 PM');
msg('date.toString() == ' + date.toDateString());
Date.prototype.toTimeString()

Returns a string representing only the time.

Mozilla and MSIE disagree on Time String format.

Mozilla
12:30:00 GMT-0500 (Eastern Standard Time)
MSIE
12:30:00 EDT
var date = new Date('7/4/1776 12:30 PM');
msg('date.toString() == ' + date.toTimeString());
Date.prototype.toLocaleString()

Returns a string representing a locale specific version of the date and time.

Date.prototype.toLocaleDateString()

Returns a string representing a locale specific version of the date.

Date.prototype.toLocaleTimeString()

Returns a string representing a locale specific version of the time.

Date.prototype.valueOf()

Returns a number representing the internal time value of the date.

Date.prototype.valueOf() - MSIE returns 0 instead of NaN
// call the prototyped valueOf() directly
msg('Date.prototype.valueOf() == ' + Date.prototype.valueOf());

// call valueOf on a real date instance
var date = new Date();
msg('date == ' + date);
msg('date.valueOf() == ' + date.valueOf());
msg('new Date(date.valueOf()) == ' + (new Date(date.valueOf())));
Date.prototype.getTime()

Return the time value. Identical to Date.prototype.valueOf.

var date = new Date(2000, 12, 7, 11, 30, 45);
msg('date.getTime() == ' + date.getTime());
msg('date.valueOf() == ' + date.valueOf());
Date.prototype.getYear()

Returns a number value representing the number of years after 1900.

Deprecated in ECMA 262 1st. Mozilla JavaScript1.2 and MSIE treat getYear as if it were getFullYear.

var date = new Date('12/22/2004');
msg('date.getYear() == ' + date.getYear());
Date.prototype.getFullYear()

Returns a number value representing the number of years in the date value when considered in the local time zone.

var date = new Date('12/22/2004');
msg('date.getFullYear() == ' + date.getFullYear());
Date.prototype.getUTCFullYear()

Returns a number value representing the number of years in the date value when considered in the UTC time zone.

var date = new Date('12/31/2004 11:59 PM');
msg('date.getUTCFullYear() == ' + date.getUTCFullYear());
Date.prototype.getMonth()

Returns the month number in the local time zone.

var date = new Date(2000, 11, 31, 23, 59);
msg('date.getMonth() == ' + date.getMonth());
Date.prototype.getUTCMonth()

Returns the month number in the UTC time zone.

var date = new Date(2000, 11, 31, 23, 59);
msg('date.getUTCMonth() == ' + date.getUTCMonth());
Date.prototype.getDate()

Returns the day of the month in the local time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getDate() == ' + date.getDate());
Date.prototype.getUTCDate()

Returns the day of the month in the UTC time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getUTCDate() == ' + date.getUTCDate());
Date.prototype.getDay()

Returns the day of the week in the local time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getDay() == ' + date.getDay());
Date.prototype.getUTCDay()

Returns the day of the week in the UTC time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getUTCDay() == ' + date.getUTCDay());
Date.prototype.getHours()

Returns the hour of the day in the local time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getHours() == ' + date.getHours());
Date.prototype.getUTCHours()

Returns the hour of the day in the UTC time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getUTCHours() == ' + date.getUTCHours());
Date.prototype.getMinutes()

Returns the minutes of the hour in the local time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getMinutes() == ' + date.getMinutes());
Date.prototype.getUTCMinutes()

Returns the minutes of the hour in the UTC time zone.

var date = new Date(2000, 12, 7, 23, 59);
msg('date.getUTCMinutes() == ' + date.getUTCMinutes());
Date.prototype.getSeconds()

Returns the seconds of the minute in the local time zone.

var date = new Date(2000, 12, 7, 23, 59, 59);
msg('date.getSeconds() == ' + date.getSeconds());
Date.prototype.getUTCSeconds()

Returns the seconds of the minute in the UTC time zone.

var date = new Date(2000, 12, 7, 23, 59, 59);
msg('date.getUTCSeconds() == ' + date.getUTCSeconds());
Date.prototype.getMilliseconds()

Returns the milliseconds of the second in the local time zone.

var date = new Date(2000, 12, 7, 23, 59, 59, 999);
msg('date.getMilliseconds() == ' + date.getMilliseconds());
Date.prototype.getUTCMilliseconds()

Returns the milliseconds of the second in the UTC time zone.

var date = new Date(2000, 12, 7, 23, 59, 59, 999);
msg('date.getUTCMilliseconds() == ' + date.getUTCMilliseconds());
Date.prototype.getTimezoneOffset()

Return the difference between the local time zone and the UTC time zone in minutes.

var date = new Date();
msg('date.getTimezoneOffset() == ' + date.getTimezoneOffset());
Date.prototype.setTime(time)

Sets the date value to the number of milliseconds in time.

var date0 = new Date(0);
var datenow = new Date();

msg('date0 == ' + date0);
msg('datenow == ' + datenow);

date0.setTime(datenow.getTime());

msg('date0 == ' + date0);
Date.prototype.setYear(year)

Sets the year value of the date to year. If year is 0 to 99, it is treated as if year + 1900 were specified.

Deprecated. Use setFullYear instead.
var date = new Date('12/22/2004');
msg('date.toDateString() == ' + date);

msg('date.setYear(2003) == ' + 
    date.setYear(2003) + ', ' + 
    date);

msg('date.setYear(20) == ' + 
    date.setYear(20) + ', ' + 
    date);
Date.prototype.setFullYear(year[, month[, day]])

Set the year value to corresponding to local time zone values of year, month and day with no conversion if year is 0 to 99. If month is not specified, the value of date.getMonth() is used instead. If day is not specified, date.getDate() is used instead.

var date = new Date('12/22/2004 23:59:59');
msg('date.toDateString() == ' + date);

msg('date.getMonth() == ' + date.getMonth());
msg('date.getDate() == ' + date.getDate());

msg('date.setFullYear(2003) == ' + 
    date.setFullYear(2003) + ', ' + 
    date);
msg('date.setFullYear(2002, 1) == ' + 
    date.setFullYear(2002, 1) + ', ' +
    date);
msg('date.setFullYear(2001, 1, 1) == ' + 
    date.setFullYear(2001, 1, 1) + ', ' + 
    date);
Date.prototype.setUTCFullYear(year[, month[, date]])

Set the year value to corresponding to local time zone values of year, month and day with no conversion if year is 0 to 99. If month is not specified, the value of date.getUTCMonth() is used instead. If day is not specified, date.getUTCDate() is used instead.

var date = new Date('12/31/2004 23:59:59');
msg('date.toDateString() == ' + date);

msg('date.getUTCMonth() == ' + date.getUTCMonth());
msg('date.getUTCDate() == ' + date.getUTCDate());

msg('date.setUTCFullYear(2003) == ' + 
    date.setUTCFullYear(2003) + ', ' + 
    date);

msg('date.setUTCFullYear(2002, 1) == ' + 
    date.setUTCFullYear(2002, 1) + ', ' +
    date);

msg('date.setUTCFullYear(2001, 1, 1) == ' + 
    date.setUTCFullYear(2001, 1, 1) + ', ' + 
    date);
Date.prototype.setMonth(month[, day])

Sets the month and day values of the date using the local time zone.

Date.prototype.setUTCMonth(month[, day])

Sets the month and day values of the date using the UTC time zone.

Date.prototype.setDate(day)

Sets the day value of the date using the local time zone.

Date.prototype.setUTCDate(date)

Sets the day value of the date using the UTC time zone.

Date.prototype.setHours(hour[, min[, sec[, ms]]])

Sets the hour and optionally minute, second and millisecond of the date using the local time zone.

Date.prototype.setUTCHours(hour[, min[, sec[, ms]]])

Set the hour and optionally minute, second and millisecond of the date using the UTC time zone.

Date.prototype.setMinutes(min[, sec[, ms]])

Sets the minutes and optionally the seconds and milliseconds of the date using the local time zone.

Date.prototype.setUTCMinutes(min[, sec[, ms]])

Sets the minutes and optionally the seconds and milliseconds of the date using the UTC time zone.

Date.prototype.setSeconds(sec[, ms])

Sets the seconds and optionally milliseconds of the date using the local time zone.

Date.prototype.setUTCSeconds(sec[, ms])

Sets the seconds and optionally milliseconds of the date using the UTC time zone.

Date.prototype.setMilliseconds(ms)

Sets the milliseconds of the date using the local time zone.

Date.prototype.setUTCMilliseconds(ms)

Sets the milliseconds of the date using the UTC time zone.

Date.prototype.toGMTString()

Deprecated. Mozilla and MSIE disagree on Date string format and the effects of old dates on daylight savings time.

Date Mozilla toUTCString MSIE toUTCString Note
7/4/1776 12:30 PM Thu, 04 Jul 1776 17:30:00 GMT Thu, 4 Jul 1776 16:30:00 UTC Mozilla uses GMT while MSIE uses UTC. MSIE problem with Daylight Savings Time in old dates
7/4/2004 12:30 PM Sun, 04 Jul 2004 16:30:00 GMT Sun, 4 Jul 2004 16:30:00 UTC GMT vs UTC but otherwise the same.
12/25/2004 12:30 PM Sat, 25 Dec 2004 17:30:00 GMT Sat, 25 Dec 2004 17:30:00 UTC ditto
var date = new Date('7/4/1776 12:30 PM');
msg('date.toGMTString() == ' + date.toGMTString());

date = new Date('7/4/2004 12:30 PM');
msg('date.toGMTString() == ' + date.toGMTString());

date = new Date('12/25/2004 12:30 PM');
msg('date.toGMTString() == ' + date.toGMTString());
Date.prototype.toUTCString()

Mozilla and MSIE disagree on Date string format and the effects of old dates on daylight savings time.

Date Mozilla toUTCString MSIE toUTCString Note
7/4/1776 12:30 PM Thu, 04 Jul 1776 17:30:00 GMT Thu, 4 Jul 1776 16:30:00 UTC Mozilla uses GMT while MSIE uses UTC. MSIE problem with Daylight Savings Time in old dates
7/4/2004 12:30 PM Sun, 04 Jul 2004 16:30:00 GMT Sun, 4 Jul 2004 16:30:00 UTC GMT vs UTC but otherwise the same.
12/25/2004 12:30 PM Sat, 25 Dec 2004 17:30:00 GMT Sat, 25 Dec 2004 17:30:00 UTC ditto
var date = new Date('7/4/1776 12:30 PM');
msg('date.toUTCString() == ' + date.toUTCString());

date = new Date('7/4/2004 12:30 PM');
msg('date.toUTCString() == ' + date.toUTCString());

date = new Date('12/25/2004 12:30 PM');
msg('date.toUTCString() == ' + date.toUTCString());
Date.parse(string)

Parses string and returns the corresponding time value in milliseconds. See Date(value) for more details on the format of the date string.

Mozilla will accept invalid dates with the incorrect number of days in a month or months in a year however will return NaN in cases where the time value is inconsistent, for example when the time implies PM but the string contains AM.

MSIE will accept invalid dates with the incorrect number of days in a month or months in a year or the time value is inconsistent with the AM/PM values.

var s = '7/4/1776 12:30 PM';
var date = Date.parse(s);
msg('Date.parse(s) == ' + date + ', ' + 
    (isNaN(date)?'-':new Date(date)));

s = '1/1/1999 13:30 AM';
date = Date.parse(s);
msg('Date.parse(s) == ' + date + ', ' + 
    (isNaN(date)?'-':new Date(date)));

s = '2/29/2001';
date = Date.parse(s);
msg('Date.parse(s) == ' + date + ', ' + 
    (isNaN(date)?'-':new Date(date)));

s = '13/29/2001';
date = Date.parse(s);
msg('Date.parse(s) == ' + date + ', ' + 
    (isNaN(date)?'-':new Date(date)));
Date.prototype.UTC(year, month[, day[, hours[, minutes[, seconds[, ms]]]]])

Returns a time value in milliseconds corresponding to the arguments. Unlike Date() called as a function, the return value is not an instance of Date and the arguments use the UTC time zone.

RegExp Objects

Regular Expressions are a means of describing and processing patterns in text using a special pattern language called a regular expression language. In JavaScript, regular expressions are used to describe patterns in string values. If you have ever performed a directory listing using wild cards (dir *.txt) you have used a kind of regular expression. The actual language used to express the patterns depends upon the program. In JavaScript, regular expressions are patterned after those found in the Perl programming language.

Regular Expressions can be created either using the RegExp constructor or by using regular expression literal expressions. A regular expression literal has the form /pattern/flags where pattern is some sequence of characters and flags are a possibly empty combination of g, i or m. Without the flags, the regular expression will only find the first matching occurence in a string, will be case-sensitive and will not consider newline characters as special. If the global flag (g) is used, then the regular expression will find all matching occurences in the string. If the case-insensitive flag (i) is used, the regular expression will ignore case when performing matches. If the multiline flag (m) is used, the pattern ^ will match the beginning of any embedded line and $ will match the end of any embedded line.

Some examples of regular expression patterns are:

/foo/
search for the first occurence of foo.
/foo/g
search for all occurences of foo.
/foo/i
search for the first occurence of foo ignoring the case of the letters.
/foo$/m
search for the first occurence of foo which is followed by a newline character or the end of the string.
Regular Expression Patterns
\

The backslash character \ is used to escape characters by either removing any special meaning they might otherwise have or to change their meaning. For example, the letter v can be used to represent the vertical tab character by escaping it as \v. Other characters which have special meanings in a regular expression, such as $ which represents the end of a string, can be escaped \$ so that they lose their special meaning and simply represent themselves; in this case the dollar sign.

If you wish to match the literal \ character, you must escape it as \\.

Regular Expression Boundary Patterns

Boundary patterns are special patterns which do not match any actual text in a string, but instead match a location. Note that boundary matches have zero size.

^

^ is used to match the boundary at the beginning of the string which is being searched. If the multiline flag is set, ^ also matches the boundary after the newline \n character in a string. If you wish to match the literal character ^ in a string, you must code it as \^ in the pattern.

var string = 'this is one line\nThis is another Line';

/*
Without the multiline flag, ^ will only match the beginning of the input
*/

msg('/^this/.test(string) == ' + /^this/.test(string));
msg('/^This/.test(string) == ' + /^This/.test(string));

/*
With the multiline flag, ^ will match the beginning of any line
*/

msg('/^this/m.test(string) == ' + /^this/m.test(string));
msg('/^This/m.test(string) == ' + /^This/m.test(string));

$

$ is used to match the boundary at the end of the string which is being searched. If the multiline flag is set, $ also matches the boundary before the newline character \n in a string. If you wish to match the literal character $ in a string, you must code it as \$ in the pattern.

var string = 'this is one line\nThis is another Line';

/*
Without the multiline flag, $ will only match the end of the input
*/

msg('/line$/.test(string) == ' + /line$/.test(string));
msg('/Line$/.test(string) == ' + /Line$/.test(string));

/*
With the multiline flag, $ will match the end of any line
*/

msg('/line$/m.test(string) == ' + /line$/m.test(string));
msg('/Line$/m.test(string) == ' + /Line$/m.test(string));

\b

\b matches the boundary between words where a word is defined as an identifier. Note that boundaries have zero size.

\b can be confusing since in regular expression patterns it represents a word boundary however in string values it represents the backspace character.

var string = 'abc.def + 123';
var regexp = /\b/g; // match any boundary between words

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);

Note that Mozilla returns the location of the match in the regexp.lastIndex for zero-width matches using \b but that MSIE will return the location following the match.

\B

\B matches a non-word boundary, that is an artificial boundary inside of a word.

var string = 'abc_def_123';
var regexp = /\B/g; // match a non-word boundary

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);

Note that Mozilla returns the location of the match in the regexp.lastIndex for zero-width matches using \B but that MSIE will return the location following the match.

Regular Expression Character Patterns

Character patterns are used to match specific characters as well as classes of characters.

The characters \ ^ $ * + ? . ( ) | { } [ ] have special meanings in regular expression patterns. If you wish to match a literal occurence of a special character you must escape it using \. Other characters can be written in a pattern normally.

.

. matches any character except the newline character.

[class]

[class] describes a character class. class is composed of one or more pairs of characters separated by the - and represent the set of characters bounded by the pair. For example, [a-z] represents the set of characters abcdefhijklmnopqrstuvwxyz.

The ^ character has a different meaning inside of a character class. When ^ occurs immediately following the opening [ of a character class, it means that the class consists of all characters which do not match the class. For example, [^a-z] represents the set of characters which are not lower case latin letters. If ^ is not the first character in a character class, it acts simply as the character ^.

var string = "abc^def";
var regexp;

regexp = /[a-z]+/;

msg('regexp.exec(string) == ' + regexp.exec(string));

regexp = /[^a-z]+/;

msg('regexp.exec(string) == ' + regexp.exec(string));

regexp = /[^^]+/;

msg('regexp.exec(string) == ' + regexp.exec(string));
[\b]

[\b] matches the backspace character. Since \b is defined to match the boundary between words, it can not be used to match the back space character \b in strings. Instead, a hack is used by writing the backspace character as a character class using [].

var string = 'this has a backspace character: \b';
var regexp = /[\b]/;

msg('regexp.test(string) == ' + regexp.test(string));
\cC

\cC matches the control character control C.

var string = '\x01\x02\x03\x04\x05';
var regexp = /\cA/g;

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);

Mozilla fails to match a control character while MSIE succeeds.

\d

Matches a digit 0, 1, 2, 3, 4, 5, 6, 7, 8 or 9

var string = 'abc123def';
var regexp = /\d/g;

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);
\D

Matches a non-digit.

var string = 'abc123def';
var regexp = /\D/g;

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);
\f

Matches a form feed character.

var string = 'abc\fdef';
var regexp = /\f/g;

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);
\n

Matches a newline character.

var string = 'abc\ndef';
var regexp = /\n/g;

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);
\r

Matches a carriage return character.

var string = 'abc\rdef';
var regexp = /\r/g;

msg('regexp.test(string) == ' + regexp.test(string));

msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext);
\s

Matches a whitespace character. In JavaScript, whitespace characters are the space, tab, form feed, vertical form feed, newline, carriage return, and \u00A0, \u2028 and \u2029.

var whitespacechars = [' ',  '\t', '\f', 
                       String.fromCharCode(11), 
                       '\n', '\r', 
                       '\u00A0', '\u2028', '\u2029'];
var whitespacenames = [' ',  '\\t', '\\f', '\\v', '\\n', '\\r', 
                       '\\u00A0', '\\u2028', '\\u2029'];

var regexp = /\s/;

for (var i = 0; i < whitespacechars.length; i++)
{
  var string = whitespacechars[i];
  var name = whitespacenames[i];

  msg('/\\s/.test("' + name + '") == ' + regexp.test(string));

  msg('regexp.lastIndex == ' + regexp.lastIndex + ', ' +
      'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
      'RegExp.rightContext == ' + RegExp.rightContext);
}

Note MSIE does not recognize \v as the vertical form feed character in strings however does recognize it in regular expression patterns. MSIE does not recognize no break space \u00A0, or the unicode line separator \u2028 or the unicode paragraph separator \u2029 as whitespace characters.

\S

Matches any non-whitespace character.

MSIE will incorrectly match no break space \u00A0, or the unicode line separator \u2028 or the unicode paragraph separator \u2029 as non-whitespace characters.

\t

Matches a tab.

\v

Matches the vertical tab character.

MSIE does support \v in regular expression patterns but does not support \v in string literals. You must code \v in strings as String.fromCharCode(11) in MSIE.

\w

Matches any word character consisting of a letter, number, underscore or digit.

\W

Matches any non-word character.

\0

Matches the NUL character.

\xHH

Matches the character whose hexadecimal character code is 0xHH. where H is a hexadecimal digit.

\uHHHH

Matches the character whose unicode character code is \uHHHH. where H is a hexadecimal digit.

Regular Expression Quantifying Patterns
X*

Matches zero or more occurences of the regular expression X. * is the same as {0,}. * by itself is greedy which means it will match as many characters in the input as possible. If modified via the ?, it becomes non-greedy meaning it will match as few characters as possible.

var regexp;
var string = 'aabbbcccdddd';

// match zero or more a characters greedily
// which will match the leading aa
regexp = /a*/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);

// match zero or more a characters non-greedily
// which will match the empty string before the leading aa
regexp = /a*?/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);
X+

Matches one or more occurences of the regular expression X. + is the same as {1,}. + by itself is greedy which means it will match as many characters in the input as possible. If modified via the ?, it becomes non-greedy meaning it will match as few characters as possible.

var regexp;
var string = 'aabbbcccdddd';

// match one or more a characters greedily
// which will match the leading aa
regexp = /a+/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);

// match one or more a characters non-greedily
// which will match the leading a
regexp = /a+?/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);
X?

Matches zero or one occurences of the regular expression X. ? is the same as {0,1}. ? modifies a greedy quantifier into a non-greedy one. characters as possible.

var regexp;
var string = 'aabbbcccdddd';

// match zero or one a characters greedily
// which will match the leading a
regexp = /a?/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);

// match zero or one a characters non-greedily
// which will match the leading empty string
regexp = /a??/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);
{N}

Matches exactly N occurences of the previous item.

var regexp;
var string = 'aabbbcccdddd';

// match exactly 2 characters 
// which will match the aa
regexp = /a{2,}/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);

// match exactly two characters non-greedily
// which will match the same as the greedy expression
regexp = /a{2,}?/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);
{N,}

Matches at least N occurences of the previous items. {N,} by itself is greedy which means it will match as many characters in the input as possible. If modified via the ?, it becomes non-greedy meaning it will match as few characters as possible.

var regexp;
var string = 'aabbbcccdddd';

// match one or more a characters greedily
// which will match the leading a
regexp = /a{1,}/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);

// match one or more a characters non-greedily
// which will match the leading a
regexp = /a{1,}?/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);
{N, M}

Matches from N to M occurences of the previous item. {N,M} by itself is greedy which means it will match as many characters in the input as possible. If modified via the ?, it becomes non-greedy meaning it will match as few characters as possible.

var regexp;
var string = 'aabbbcccdddd';

// match 2 to 3 b characters greedily
// which will match the leading all three b characters
regexp = /b{2,3}/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);

// match 2 to 3 b characters non-greedily
// which will match the first two b characters
regexp = /b{2,3}?/;
msg('regexp.test(string) == ' + regexp.test(string));
msg('RegExp.lastMatch == ' + RegExp.lastMatch);
Regular Expression Logical Patterns
XY

XY matches regular expression X followed by the match for regular expression Y.

var regexp = /XY/;

msg('regexp.exec("XY") == ' + regexp.exec("XY"));
msg('regexp.exec("XZ") == ' + regexp.exec("XZ"));
msg('regexp.exec("ZY") == ' + regexp.exec("ZY"));
X|Y

X|Y matches regular expression X or regular expression Y.

var regexp = /X|Y/;

msg('regexp.exec("XY") == ' + regexp.exec("XY"));
msg('regexp.exec("XZ") == ' + regexp.exec("XZ"));
msg('regexp.exec("ZY") == ' + regexp.exec("ZY"));
X(?= Y)

X(?=Y) matches regular expression X if it is followed by a match for regular expression Y. This is called a lookahead pattern.

var regexp = /X(?=Y)/;

msg('regexp.exec("XY") == ' + regexp.exec("XY"));
msg('regexp.exec("XZ") == ' + regexp.exec("XZ"));
X(?! Y)

X(?!Y) matches regular expression X if it is not followed by a match for regular expression Y. This is called a negative lookahead pattern.

var regexp = /X(?!Y)/;

msg('regexp.exec("XY") == ' + regexp.exec("XY"));
msg('regexp.exec("XZ") == ' + regexp.exec("XZ"));
Regular Expression Grouping Patterns
(X)

(X) matches the same pattern as the regular expression X alone but introduces the concept of capturing parentheses. Matching pairs of parentheses () are used in regular expressions to group parts of a regular expression into a single unit which can treated as a single pattern. Parentheses capture the matches into a captures array which can be used to retrieve sub matches. If no matches are found, the captures array is null. See Capture Arrays.

(?:X)

(?:X) matches the same pattern as regular expression X but does not create an entry in the captures array. These non-capturing parentheses are useful when it is necessary to group items together in the regular expression but you do not wish to record the submatch in the capturing array.

// modify Array.prototype.toString to 
// wrap strings in quotes and to show undefined values
Array.prototype.toString = function()
{
  var s = '';
  for (var i = 0; i < this.length; i++)
  {
    if (s)
    {
      s += ',';
    }
    switch (typeof this[i])
    {
      case 'string':
        s += "'" + this[i] + "'";
        break;
      case 'undefined':
        s += 'undefined';
        break;
      default:
        s += this[i];
        break;
    }
  }
  return s;
}

var regexp = /((?:a)|(?:ab))((?:c)|(?:bc))/;

msg('regexp.exec("abc") == ' + regexp.exec("abc"));
\N

When N is a positive integer, \N is a back reference to the Nth matching capturing parentheses match.

Back references are particularly useful for matching pairs of strings such as the start and end tags of markup.

var string = '<tag>content</tag>'
var regexp = /<(\w+)>(.*)<\/\1>/;

msg('regexp.test(string) == ' + regexp.test(string));
msg('tag name == ' + RegExp.$1 + ', contents == ' + RegExp.$2);
RegExp(pattern[, flags])

If the RegExp(pattern) constructor is called (without the flags argument), and pattern is an instance of RegExp, then it returns the instance unchanged. Otherwise, the function call creates a new instance of RegExp and returns the result.

When creating an instance of a RegExp using the new operator

regexp = new RegExp(pattern, flags)
  • If pattern is a RegExp and flags is defined, then a TypeError will be thrown.
  • If pattern is undefined, pattern is treated as the empty string otherwise pattern is converted to a string.
  • If flags is undefined, flags is treated as the empty string otherwise flags is converted to a string.

If pattern is not a string representing a regular expression, or if flags contains characters other than g m i or if flags has repeated characters, a SyntaxError is thrown.

regexp.global is set to true if flags contains g otherwise false.

regexp.ignoreCase is set to true if flags contains i otherwise false.

regexp.global is set to true if flags contains g otherwise false.

RegExp has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete RegExp
msg('Before delete: typeof RegExp == ' + typeof RegExp);
msg('(delete RegExp) == ' + (delete RegExp));
msg('After delete: typeof RegExp == ' + typeof RegExp);
// attempt to assign to RegExp
RegExp = 'foo';
msg('After RegExp = \'foo\': RegExp == ' + RegExp);
RegExp.prototype

RegExp.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

RegExp.prototype.constructor

Returns a reference to the RegExp constructor.

RegExp.prototype.exec(string)

Performs a regular expression match on the string argument returning a capturing array containing the results of the match or null if there was no match.

var regexp;
var string = 'abc';
var result;

msg('exec returns null when no match is found');
regexp = /nomatch/;
result = regexp.exec(string);
msg('result == ' + result);

msg('exec returns a captures array when matches are found');
regexp = /abc/;
result = regexp.exec(string);
msg('result == ' + result);
msg('result instanceof Array: ' + (result instanceof Array));
msg('result.length == ' + result.length);

msg('exec returns submatches in the captures array ' +
    'when capturing parentheses appear in the ' + 
    'regular expression');
regexp = /(a)/;
result = regexp.exec(string);
msg('result == ' + result);
msg('result instanceof Array: ' + (result instanceof Array));
msg('result.length == ' + result.length);

Capture Arrays

Consider the following regular expression:

/((a)|(ab))((c)|(bc))/

The matches are placed into the captures array according to the position of the left parenthesis containing the sub patterns. To illustrate this example, let captures represent the captures array returned from a call to RegExp.prototype.exec() and number the capturing left parentheses in the regular expression from the left starting at 1 as follows:

/(1 (2 a)|(3 ab)) (4 (5 c)|(6 bc))/
  1. The captures[0] item will contain the substring which matched the entire pattern.
  2. The captures[1] item will contain the characters matching the capturing parenthesis labelled 1. It will contain the leading characters matching either a or ab or undefined if there was no match.
  3. The captures[2] item will contain the characters matching the capturing parenthesis labelled 2. It will contain the leading characters matching a or undefined if there was no match.
  4. The captures[3] item will contain the characters matching the capturing parenthesis labelled 3. It will contain the leading characters matching ab or undefined if there was no match.
  5. The captures[4] item will contain the characters matching the capturing parenthesis labelled 4. It will contain the characters matching either c or bc which follow the characters which matched parenthesis 1 or undefined if there is no match.
  6. The captures[5] item will contain the characters matching the capturing parenthesis labelled 5. It will contain the c which follows the characters which matched parenthesis 1 or undefined if there is no match.
  7. The captures[6] item will contain the characters matching the capturing parenthesis labelled 6. It will contain the characters matching bc which follows the characters which matched parenthesis 1 or undefined if there is no match.
// modify Array.prototype.toString to 
// wrap strings in quotes and to show undefined values
Array.prototype.toString = function()
{
  var s = '';
  for (var i = 0; i < this.length; i++)
  {
    if (s)
    {
      s += ',';
    }
    switch (typeof this[i])
    {
      case 'string':
        s += "'" + this[i] + "'";
        break;
      case 'undefined':
        s += 'undefined';
        break;
      default:
        s += this[i];
        break;
    }
  }
  return '[' + s + ']';
}

var regexp = /((a)|(ab))((c)|(bc))/;

msg('regexp.exec("abc") == ' + regexp.exec("abc"));
Mozilla: ['abc','a','a',undefined,'bc',undefined,'bc']
MSIE:    ['abc','a','a','',       'bc','',       'bc']

Note that Mozilla correctly returns undefined for capturing parentheses which were not matched, however MSIE incorrectly returns the empty string '' instead.

MSIE only

MSIE adds a property lastIndex to the captures array. captures.lastIndex returns the next position in the string following the match.

var regexp = /a/;
var string = 'dcba';
var result = regexp.exec(string);
msg('result.lastIndex == ' + result.lastIndex);

The ECMAScript Standard provides a number of illustrative examples which can help in understanding how regular expressions work and how capture arrays are populated.

/*
 * examples from the ecma 262 3rd edition 
 */
// modify Array.prototype.toString to 
// wrap strings in quotes and to show undefined values
Array.prototype.toString = function()
{
  var s = '';
  for (var i = 0; i < this.length; i++)
  {
    if (s)
    {
      s += ',';
    }
    switch (typeof this[i])
    {
      case 'string':
        s += "'" + this[i] + "'";
        break;
      case 'undefined':
        s += 'undefined';
        break;
      default:
        s += this[i];
        break;
    }
  }
  return '[' + s + ']';
}

function test(regexp, string, expected)
{
  var result = regexp.exec(string);

  msg(
  'Test ' + ((result.toString() == expected) ? 
              'Passed' : 
              'Failed') + ' : ' +
   regexp + '.exec("' + string + '")'
   );  

  msg('e == ' + expected);
  msg('r == ' + result);
  msg('<br>');

}

msg('ECMA 262 3rd Section 15.10.2.3 Disjunction<br>');

test(/a|ab/, 
     'abc', 
     ['a']); 

// MSIE returns empty strings instead of undefined
test(/((a)|(ab))((c)|(bc))/, 
     'abc', 
     ['abc', 'a', 'a', undefined, 'bc', undefined, 'bc']);

msg('ECMA 262 3rd Section 15.10.2.5 Term<br>');

test(/a[a-z]{2,4}/, 
     'abcdefghi', 
     ['abcde']);

test(/a[a-z]{2,4}?/,
     'abcdefghi',
     ['abc']);

test(/(aa|aabaac|ba|b|c)*/,
     'aabaac',
     ['aaba', 'ba']);

// MSIE fails Step 4 of Repeat Matcher 
// to clear the Atom's captures each time Atom is repeated.
test(/(z)((a+)?(b+)?(c))*/,
     'zaacbbbcac',
     ['zaacbbbcac', 'z', 'ac', 'a', undefined, 'c']);

// MSIE returns empty strings instead of undefined
test(/(a*)*/,
     'b',
     ['', undefined]);

test(/(a*)b\1+/,
     'baaaac',
     ['b', '']);

msg('ECMA 262 3rd Section 15.10.2.8 Atom<br>');

test(/(?=(a+))/,
    'baaabac',
    ['', 'aaa']);

test(/(?=(a+))a*b\1/,
     'baaabac',
     ['aba', 'a']);

test(/(.*?)a(?!(a+)b\2c)\2(.*)/,
     'baaabaac',
     ['baaabaac', 'ba', undefined, 'abaac']);
MSIE differences

MSIE fails to record undefined in the capturing array and instead uses the empty string ''.

MSIE fails (z)((a+)?(b+)?(c))*/.exec("zaacbbbcac") since it appears to not follow the ECMA 262 standard and does not clear the captures array of an atom each time it is repeated.

RegExp.prototype.test(string)

Performs a regular expression match on the string argument returning true if a match was found or false if none found.

msg('/foo/.test("This is foo bar!") == ' + 
     /foo/.test("This is foo bar!"));
RegExp.prototype.toString()

Returns a string representing the source of the regular expression.

var regexp;

// test empty regular expression
regexp = new RegExp();
msg('regexp.toString() == ' + regexp.toString());

// test a regular expression with flags
regexp = new RegExp('foo', 'mig');
msg('regexp.toString() == ' + regexp.toString());
regexp.toString() and empty regular expressions

Mozilla correctly returns /(?:)/ for an empty regular expression.

MSIE incorrectly returns // for an empty regular expression which is problem since // begins a JavaScript line comment.

regexp.toString() and flags

Note that for regular expresison /foo/mig, Mozilla returns /foo/gim with the flags in gim order while MSIE returns /foo/igm with the flags in igm order.

RegExp.index
MSIE only

read only property that returns index in string of last match.

msg('typeof RegExp.index == ' + typeof RegExp.index);
msg('RegExp.index == ' + RegExp.index);

msg('"foobar".match(/bar/) == ' + "foobar".match(/bar/));
msg('RegExp.index == ' + RegExp.index);
RegExp.input, RegExp.$_
Non-Standard, but supported by Mozilla and MSIE

RegExp.input is a non-standard property of the RegExp constructor. $_ is a synonym for input.

Mozilla and MSIE both will set the value of RegExp.input to the string value last searched by a regular expression.

Mozilla also allows RegExp.input to be be set, so that any call to the exec() or test() methods of a regular expression instance will use the input value as the string to be searched if there is no argument specified. MSIE does not support this extension.

msg('check the initial type and value of RegExp.input');
msg('typeof RegExp.input == ' + typeof RegExp.input);
msg('RegExp.input == ' + RegExp.input);
msg('RegExp.$_ == ' + RegExp.$_);

msg('perform a search on a string and check RegExp.input');
msg('"foobar".match(/bar/) == ' + "foobar".match(/bar/));
msg('RegExp.input == ' + RegExp.input);
msg('RegExp.$_ == ' + RegExp.$_);

msg('attempt to set RegExp.input then perform a search using');
msg('instance.exec(). This works in Mozilla, but not MSIE');
msg('RegExp.input = "barfoo" ' + (RegExp.input = "barfoo"));
msg('/bar/.exec() == ' + /bar/.exec());
msg('RegExp.input == ' + RegExp.input);
msg('RegExp.$_ == ' + RegExp.$_);

msg('cross browser/standard approach. works in Mozilla and MSIE');
msg('/bar/.exec("barfoo") == ' + /bar/.exec("barfoo"));
msg('RegExp.input == ' + RegExp.input);
msg('RegExp.$_ == ' + RegExp.$_);
RegExp.lastIndex
MSIE only

RegExp.lastIndex returns the next position in the string following the match or -1 if there is no match, -1 if lastIndex exceeds the length of the string.

var s;   // search string
var r;   // search regular expression

msg('check the initial type and value of RegExp.lastIndex');
msg('typeof RegExp.lastIndex == ' + typeof RegExp.lastIndex);
msg('RegExp.lastIndex == ' + RegExp.lastIndex);

msg('set search string: s = ' + (s = "foobarfoobar"));

msg('set RegExp.lastIndex = ' + (RegExp.lastIndex = 8));
msg('perform a non global search on a string and check RegExp.lastIndex');
msg('for non global searches lastIndex should be ignored');
msg('set regular expression: r = ' + (r = /bar/));
msg('r.exec(s) == ' + r.exec(s));
msg('RegExp.lastIndex == ' + RegExp.lastIndex);

msg('repeat a non global search on a string and check RegExp.lastIndex');
msg('r.exec(s) == ' + r.exec(s));
msg('RegExp.lastIndex == ' + RegExp.lastIndex);

msg('perform a global search on a string and check RegExp.lastIndex');
msg('set regular expression: r = ' + (r = /bar/g));
msg('r.exec(s) == ' + r.exec(s));
msg('RegExp.lastIndex == ' + RegExp.lastIndex);
msg('repeat a non global search on a string and check RegExp.lastIndex');
msg('r.exec(s) == ' + r.exec(s));
msg('RegExp.lastIndex == ' + RegExp.lastIndex);

msg('attempt to set RegExp.lastIndex then perform a search');
msg('MSIE treats RegExp.lastIndex as readonly');
msg('RegExp.lastIndex = ' + (RegExp.lastIndex = 2));
msg('r.exec(s) == ' + r.exec(s));
msg('RegExp.lastIndex == ' + RegExp.lastIndex);
RegExp.lastMatch, RegExp['$&']
Non standard, but supported by Mozilla and MSIE.

Returns the last match made by a regular expression.

var string = "this is a test.";
var regularexpression = /\w+/;
regularexpression.test(string);
msg('RegExp.lastMatch == ' + RegExp.lastMatch + 
    ', RegExp[\'$&\'] == ' + RegExp['$&']);
RegExp.lastParen, RegExp['$+']
Non standard, but supported by Mozilla and MSIE.

Returns the last item in the capturing array, if any.

var string = "this is a test.";
var regexp = /(\w+) (\w+)/;
var result = regexp.exec(string);
msg('RegExp.lastMatch    == ' + RegExp.lastMatch + '<br>' + 
    'RegExp.lastParen == ' + RegExp.lastParen + '<br>' +
    'RegExp[\'$+\'] == ' + RegExp['$+']  + '<br>' +
    'result[result.length - 1] == ' + result[result.length -1]);
RegExp.leftContext, RegExp.$`
Non standard, but supported by Mozilla and MSIE.

Returns the leading portion of the string before the match.

var string = "this is a test.";
var regularexpression = / is (\w+) (\w+)/;
regularexpression.test(string);
msg('RegExp.lastMatch    == ' + RegExp.lastMatch + ', ' + 
    'RegExp.leftContext == ' + RegExp.leftContext + ', ' + 
    'RegExp[\'$`\'] == ' + RegExp['$`']);
RegExp.rightContext, RegExp.$'
Non standard, but supported by Mozilla and MSIE.

Returns the trailing portion of the string after the match.

var string = "this is a test.";
var regularexpression = /(\w+)/;
regularexpression.test(string);
msg('RegExp.lastMatch    == ' + RegExp.lastMatch + ', ' + 
    'RegExp.rightContext == ' + RegExp.rightContext +  ', ' + 
    'RegExp[\'$\'\'] == ' + RegExp['$\'']);
RegExp.$1 - RegExp.$9
Non standard, but supported by Mozilla and MSIE.

RegExp.$N where N is a digit from 1 to 9 returns the corresponding item from the captures array.

var string = "this is a test.";
var regexp = /((\w+) (\w+) (\w+) (\w+)(.*))/;
var result = regexp.exec(string);

msg('RegExp.lastMatch    == ' + RegExp.lastMatch);
for (var i = 1; i < result.length; i++)
{
  msg('RegExp[\'$' + i + '\'] == ' + RegExp['$' + i] +
      '; ' + 
      'result[' + i + '] == ' + result[i]);
}
regexp.source

Returns a string representing the source of the regular expression (without the bounding /. This is the same value as would have been passed to RegExp(pattern) during construction.

var regexp;
var string = "this is a Test.";

msg('test regexp.toSource() for an empty regular expression');

regexp = new RegExp();
msg('regexp.source  == ' + regexp.source);

msg('test /([A-Z]\w+)/');

regexp = /([A-Z]\w+)/;
msg('regexp.source  == ' + regexp.source);

msg('test if regexp.source is readonly');

try
{
  regexp.source = '/(\w+)/';
  msg('Test regexp.source is readonly ' + 
      (regexp.source  ==  '([A-Z]\\w+)' ? 'passed.' : 'failed.'));
}
catch(e)
{
  msg('regexp.source should be readonly ' + 
      'but not cause an error. ' +  
      e.name + ': ' + e.message );
}
regexp.global

Read only property which returns true if the regular expression has the global g flag is set.

var regexp;
var string = "this is a Test.";

msg('test /(\w+ )*/');

regexp = /(\w+ )*/;
msg('regexp.global  == ' + regexp.global);
msg('string.match(regexp) == ' + string.match(regexp));

msg('test /(\w+ )*/g');

regexp = /(\w+ )*/g;
msg('regexp.global  == ' + regexp.global);
msg('string.match(regexp) == ' + string.match(regexp));

msg('test if regexp.source is readonly');

try
{
  regexp.global = false;
  msg('Test regexp.global is readonly ' + 
      (regexp.global == true  ? 'passed.' : 'failed.'));
}
catch(e)
{
  msg('regexp.global should be readonly ' + 
      'but not cause an error. ' +  
      e.name + ': ' + e.message);
}
regexp.ignoreCase

Read only property which returns true if the reqular expression has the ignore case i flag set.

var regexp;
var string = "this is a Test.";

msg('test /test/');

regexp = /test/;
msg('regexp.ignoreCase  == ' + regexp.ignoreCase);
msg('string.match(regexp) == ' + string.match(regexp));

msg('test /test/i');

regexp = /test/i;
msg('regexp.ignoreCase  == ' + regexp.ignoreCase);
msg('string.match(regexp) == ' + string.match(regexp));

msg('test if regexp.ignoreCase is readonly');

try
{
  regexp.ignoreCase = false;
  msg('Test regexp.ignoreCase is readonly ' + 
      (regexp.ignoreCase == true  ? 'passed.' : 'failed.'));
}
catch(e)
{
  msg('regexp.ignoreCase should be readonly ' + 
      'but not cause an error. ' +  
      e.name + ': ' + e.message);
}
regexp.multiline

Read only property which returns true if the multiline m flag is set.

var string = "this is a test.\r\nThis is another test.";

msg('test $ without multiline');
var regexp = /a test.$/;
msg('regexp.multiline  == ' + regexp.multiline);
msg('string.match(regexp) == ' + string.match(regexp));

msg('test $ with multiline');

regexp = /a test.$/m;
msg('regexp.multiline  == ' + regexp.multiline);
msg('string.match(regexp) == ' + string.match(regexp));

msg('test if regexp.multiline is readonly');

try
{
  regexp.multiline = false;
  msg('Test regexp.multline is readonly ' + 
      (regexp.multiline == true  ? 'passed.' : 'failed.'));
}
catch(e)
{
  msg('regexp.multiline should be readonly ' + 
      'but not cause an error. ' +  
      e.name + ': ' + e.message);
}
regexp.lastIndex

If the global flag is set on the regular expression regexp, regexp.lastIndex is used to report and set the position in the string where the next match will begin. If the regular expression does not have the global flag set, then lastIndex should have no effect on matches.

var s;   // search string
var r;   // search regular expression

msg('create a regular expression without a global flag');
msg('set search string: s = ' + (s = "foobarfoobar"));
msg('set regular expression: r = ' + (r = /bar/));
msg('<br>');

msg('check the initial type and value of r.lastIndex');
msg('typeof r.lastIndex == ' + typeof r.lastIndex);
msg('r.lastIndex == ' + r.lastIndex);
msg('<br>');

msg('perform a non global search on a string and check r.lastIndex');
msg('r.exec(s) == ' + r.exec(s));
msg('r.lastIndex == ' + r.lastIndex);
msg('<br>');

msg('repeat a non global search on a string and check RegExp.lastIndex');
msg('for non global searches lastIndex should be ignored');
msg('r.exec(s) == ' + r.exec(s));
msg('r.lastIndex == ' + r.lastIndex);
msg('<br>');

msg('attempt to set lastIndex on a non-global');
msg('regular expression then perform a search.');
msg('r.lastIndex = ' + (r.lastIndex = 2));
msg('r.exec(s) == ' + r.exec(s));
msg('r.lastIndex == ' + r.lastIndex);
msg('<br>');

msg('create a regular expression with a global flag');
msg('set regular expression: r = ' + (r = /bar/g));
msg('r.lastIndex == ' + r.lastIndex);
msg('<br>');

msg('perform a global search on a string and check RegExp.lastIndex');
msg('r.exec(s) == ' + r.exec(s));
msg('r.lastIndex == ' + r.lastIndex);
msg('<br>');

msg('repeat a non global search on a string and check r.lastIndex');
msg('r.exec(s) == ' + r.exec(s));
msg('r.lastIndex == ' + r.lastIndex);
msg('<br>');

msg('attempt to set r.lastIndex then perform a search');
msg('r.lastIndex = ' + (r.lastIndex = 2));
msg('r.exec(s) == ' + r.exec(s));
msg('r.lastIndex == ' + r.lastIndex);
MSIE differs from the ECMAScript Standard and Mozilla on non global regular expressions.

MSIE allows regexp.lastIndex to be used in non global regular expressions. MSIE will return the position in the string following the match for a non global regular expression, but on repeated searches will begin searching at the beginning of the string rather than at the position contained in lastIndex. MSIE also allows lastIndex to be set in non global regular expressions.

Error Objects

Whenever a runtime error occurs, an Error object is thrown which describes the error condition. Error serves as the base class for the other native Error objects: EvalError, RangeError, ReferenceError, SyntaxError and TypeError. Error and its child Objects can serve as the base class for user-defined error classes as well.

Error(message)

The Error constructor creates new instances of the Error Object when called as a part of a new expression or when called as a function.

var error = new Error('this is an error message');

msg('error.name == ' + error.name);
msg('error.message == ' + error.message);

Error has property attribute {DontEnum} which means it does not appear in for-in loops, can be deleted and can be the target of an assignment.

Mozilla adds the {DontDelete} property attribute which means Mozilla will not delete it.

// attempt to delete Error
msg('Before delete: typeof Error == ' + typeof Error);
msg('(delete Error) == ' + (delete Error));
msg('After delete: typeof Error == ' + typeof Error);
// attempt to assign to Error
Error = 'foo';
msg('After Error = \'foo\': Error == ' + Error);
Error.prototype

Error.prototype has property attributes {DontEnum}, {DontDelete} and {ReadOnly} which means it will not appear in for-in loops, can not be deleted and can not be changed by assignment although its properties may be modified.

Error.prototype.constructor

Returns a reference to the Error constructor.

Error.prototype.name

Error.prototype.name is initially set to 'Error' however can be overwritten in instances.

msg('Error.prototype.name == ' + Error.prototype.name);

// create an Error instance
var error = new Error('foo');
msg('error.name == ' + error.name);

// attempt to change name
error.name = 'MyError';
msg('error.name == ' + error.name);
Error.prototype.message

Error.prototype.message is initially set to the null string but in instances is initialized to the message argument passed in the constructor however it can be overwritten in instances.

msg('Error.prototype.message == ' + Error.prototype.message);

// create an Error instance
var error = new Error('foo');
msg('error.message == ' + error.message);

// attempt to change message
error.message = 'bar!';
msg('error.message == ' + error.message);
Error.prototype.toString()

Error.prototype.toString returns a string representation of an Error instance.

Mozilla's version of Error.prototype.toString will return a string consisting of the error name, a colon and space : following the error message.

MSIE's version of Error.prototype.toString will return the default value '[object Error]' which is much less use however it can be overridden to produce the same result as Mozilla.

// default Error.prototype.toString
var error = new Error('this is an error');
msg('error == ' + error);

// override MSIE's Error.prototype.toString
// override MSIE's Error.prototype.toString
if (typeof (new Error).number == 'number')
{
  // number is an MSIE only property
  Error.prototype.toString = function () 
  {
    return this.name + ': ' + this.message;
  };
}

msg('error == ' + error);
error.stack
error.lineNumber
Mozilla Only

Mozilla provides additional properties on Error objects:

stack
contains an encoded description of the function call stack where the error was initially thrown. stack contains a line (string terminated via a newline \n) for each stack frame encoded as:
function(argumentvalues)@pageurl:linenumber\n

The stack frame beginning at the global scope will have an empty function(argumentvalues).

lineNumber
contains the line number where the error occured.
/*
 * Illustrate the use of additional error properties in Mozilla
 * f1() calls f2('foo') which throws a runtime error.
 * 
 * this example parses the stack obtaining the names, 
 * arguments, and line numbers of the functions on the
 * stack when the error occured.
 */

function f1()
{
  f2('foo');
}

function f2(v)
{
  try
  {
    // cause a reference error
    v = b;
  }
  catch(e)
  {
    msg('name: ' + e.name);
    msg('message: ' + e.message);
    msg('lineNumber: ' + e.lineNumber);

    msg('stack:<br>' + e.stack + '<br>');
    var lines = e.stack.split('\n');
    var regexpstack = /((\w+)\((.*)\))?@(.*):(\d+)/;

    for (var i = 0; i < lines.length; i++)
    {
      if (lines[i])
      {
        msg('');
        msg('frame ' + i + ' == ' + lines[i]);
        var capture = regexpstack.exec(lines[i]);
        if (capture)
        {
          msg('function call == ' + capture[1]);
          msg('function name == ' + capture[2]);
          msg('function args == ' + capture[3]);
          msg('function url  == ' + capture[4]);
          msg('function line == ' + capture[5]);
        }
      }
    }
  }
}

f1();
EvalError

Mozilla and MSIE do not throw EvalError for indirect uses of eval or assignments to eval which is allowed by ECMAScript 16. Errors.

RangeError

Thrown by Number.prototype.toFixed(fractionDigits), Number.prototype.toExponentional(fractionDigits) and Number.prototype.toPrecision(fractionDigits). Supported by both Mozilla and MSIE however Mozilla extends the valid range of fractionDigits.

ReferenceError

MSIE fails to detect e instanceof ReferenceError when a reference error occurs even though it defines ReferenceError as a function.

try
{
  var a = b;
}
catch(e)
{
  msg('Exception is ' + 
      ((e instanceof ReferenceError) ? '' : 'not ') + 
      ' an instance of  ReferenceError ' +  
      e.name + ': ' + e.message );
}
SyntaxError

A SyntaxError occurs when an error occurs parsing the source of a JavaScript program.

When a syntax error occurs outside of an eval context, MSIE throws the error before running and can not capture it via a window.onerror error handler,. Mozilla can capture the error via window.onerror but not via a try catch block.

try
{
  // cause a SyntaxError
  var a * b = c;
}
catch(e)
{
  msg('Exception is ' + 
      ((e instanceof SyntaxError) ? '' : 'not ') + 
      ' an instance of  SyntaxError ' +  
      e.name + ': ' + e.message);
}

Both Mozilla and MSIE will throw SyntaxError when eval is called with invalid syntax.

try
{
  eval('var a * b = c;');
}
catch(e)
{
  msg('Exception is ' + 
      ((e instanceof SyntaxError) ? '' : 'not ') + 
      ' an instance of  SyntaxError ' + 
      e.name + ': ' + e.message
      );
}
TypeError

A TypeError is thrown when the type of an operand is incompatible with the operation.

try
{
  // Math does not have a constructor
  // so this will fail. 
  // According to 8.6.2 Internal Properties and Methods,
  // this should throw a TypeError
  var math = new Math(); 
}
catch(e)
{
  msg('Exception is ' + 
      ((e instanceof TypeError) ? '' : 'not ') + 
      ' an instance of  TypeError ' + 
      e.name + ': ' + e.message
      );
}
URIError

A URIError is thrown when one of the global URI functions decodeURI, encodeURI, decodeURIComponent or encodeURIComponent encounters an error.

// invalid character for URI functions
var invalidchar = String.fromCharCode(0xDC00 + 1)
try
{
  msg('encodeURIComponent(invalidchar) == ' + 
       encodeURIComponent(invalidchar));
}
catch(e)
{
  msg('Exception: ' + e.name + ': ' + e.message);
}

Links

home | up | topabout: