JavaScript™ (also known as ECMAScript or JScript) is an interpreted, object-oriented programming language commonly used throughout the web to provide interactive features to web pages. This article introduces JavaScript, outlines some of the basic principles behind programming using JavaScript and illustrates the differences between the different implementations available in Mozilla and Internet Explorer.
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.
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.
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
| 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.
| 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
| 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, the experimental online JavaScript Test Suite and JavaScript Test Results
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.
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.
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>
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.
<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>
<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.
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.
Ever since Kernighan and Ritchie's The
(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.C
Programming Language
"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 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.
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:
msg('hello, world');
Run this example by selecting the JavaScript version and then clicking the execute button.
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.
/*
* 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:
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.
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.
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.
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:
myobject.propnamemyobject['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.
// 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:
// 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.
// 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.
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.
/*
* 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:
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:
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;
Data types in JavaScript are divided into two categories:
Primitive types whose members are primitive values. The primitive types in JavaScript consist of Undefined, Null, Boolean, Number and String.
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.
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.
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.
The Boolean primitive type has two values:
true and false. Boolean primitive
values are not the same as instances of Boolean
Objects.
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.
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'));
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)
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.
delete operator. Any
attempt to delete the property is ignored without
error.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.
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);
}
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 Infinityotherwise 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 NaN …
Number(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"));
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.
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.
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.
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}.
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.
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);
}
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:
calleea {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();
lengtha {DontEnum} property which contains the number of actual arguments in the function call.
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…
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…
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);
}
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);
}
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
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();
| 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 |
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');
[]) OperatorSyntax
expression[propertyexpression]
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"]);
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.
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);
}
}
[] 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]);
.)
Operator.
())
Operatorgrouping and function call
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');
}
}
.
!) OperatorUnary Logical Not (!) converts the value to
boolean, then returns false if the value was
true and true otherwise.
~) OperatorUnary 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).
msg('~(+1) == ' + ~(+1))
msg('~(-1) == ' + ~(-1));
msg('~0x0f) == ' + ~0x0f);
msg('~(NaN) == ' + ~(NaN));
msg('~(0) == ' + ~(0));
msg('~(\'1\') == ' + ~('1'));
msg('~(\'a\') == ' + ~('a'));
++) OperatorThe 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.
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);
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');
}
--) OperatorThe 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.
+)
Operatorunary + 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);
-)
Operatorunary - 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)
OperatorThe typeof operator returns a string value
representing the primitive type of its operand.
| 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 |
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) OperatorThe void operator evaluates an expression but
discards any return value and returns
undefined.
msg('void (1+2) == ' + void (1+2));
delete)
OperatorThe 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}.
// 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);
*) OperatorMultiplication * 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.
msg('2 * 2 == ' + (2*2));
msg('"2" * "2" == ' + ("2" * "2"));
msg('"a" * "b" == ' + ("a" * "b"));
/) OperatorDivision / 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.
msg('1 / 2 == ' + (1 / 2));
msg('1 / 0 == ' + (1 / 0));
msg('"1" / "2" == ' + ("1" / "2"));
msg('"a" / "b" == ' + ("a" / "b"));
%) OperatorThe 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.
NaN, the result in NaN.Infinity, or the
right operand is 0, the result is
NaN.0 and the right
operand is not Infinite, the result is
0.left*right*q
for the largest integer q which has the same
sign of left/right such that q <=
left/right.
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);
+)
OperatorDepending 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.
// 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);
-)
OperatorThe 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");
.
<<)
OperatorLeft 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.
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));
>>) OperatorSigned 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.
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));
>>>) OperatorUnSigned 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.
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));
.
<)
OperatorPerforms either a numeric or string comparison returning
true if the left operand is less than 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. If
during the numeric comparison, one of the operands evaluates
to NaN, then undefined is returned
which is equivalent to false.
msg('1 < 2 == ' + (1 < 2));
msg('NaN < 1 == ' + (NaN < 1));
msg('1 < Infinity == ' + (1 < Infinity));
msg('"10" < 2 == ' + ("1" < 2));
msg('1 < "a" == ' + (1 < "a"));
msg('"a" < "b" == ' + ("a" < "b"));
It appears that step 3 in ECMAScript 11.8.5 The Abstract Relational Comparison Algorithm is incorrect, since both Mozilla and MSIE appear to use or instead of and when deciding to perform string comparison.
>)
OperatorPerforms either a numeric or string comparison returning
true if the left operand is greater than 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.
<=) OperatorPerforms 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.
>=)
OperatorPerforms 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) OperatorTests 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.
// 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) OperatorTests 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.
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);
}
==) OperatorReturns 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
comparisonx - 0 == y - 0 forces numeric
comparison!x == !y forces boolean comparisonundefined == undefinedtrue
msg('undefined == undefined ' + (undefined == undefined));
null == nulltrue
msg('null == null ' + (null == null));
null == undefined or undefined ==
nulltrue
msg('null == undefined ' + (null == undefined));
msg('undefined == null ' + (undefined == null));
typeof x, typeof y are both
"string"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"NaN, return false+0 and y
is -0 (or vice-versa), return
truetrue otherwise return
falseTo 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"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"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));
typeof x is
"number" and typeof y is
"string" or vice-versa"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"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"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);
!=) Operatorreturn 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);
===) OperatorPerforms a strict equality comparison on it operands as defined below.
The following discussion uses x === y as
the example equality test expression.
typeof x differs from typeof
yfalseundefined === undefinedtrue
msg('undefined === undefined ' + (undefined === undefined));
null === nulltrue
msg('null === null ' + (null === null));
typeof x, typeof y are
"number"NaN, return false+0 and y
is -0 (or vice-versa), return
truetrue 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"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));
!==) Operatorreturn false if left === right
is true otherwise return true.
&)
OperatorBinary 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.
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));
^)
OperatorBinary 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.
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));
|) OperatorBinary 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.
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));
&&) Operatorreturns 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);
||)
Operatorreturns 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);
?:)
OperatorThe 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);
.
=) OperatorThe 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);
op=) OperatorsThe compound assignment left op= right is the
equivalent for the expression
left = left op right
where op is one of *,
/, %, -,
<<, >>,
>>>, &, ^
or |.
,) OperatorThe 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));
var
Statementconst
StatementA 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);
}
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.
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.
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 statements are written as:
Expression;
Where Expression can not begin with a brace
{ or function.
if StatementThe 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');
}
switch
StatementThe 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 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.
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;
}
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);
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.
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]);
}
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.
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;
}
}
}
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;
}
}
}
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.
try,
catch and finally StatementsExample 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');
}
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';
Object
ObjectsFunction
ObjectsArray
ObjectsString
ObjectsBoolean
ObjectsNumber
ObjectsDate ObjectsRegExp
ObjectsMath ObjectError
ObjectsJavaScript 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 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 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.
ExampleexampleExample, e.g.
example = new Example().Example.prototype.sharedPropertyExample, e.g.
example.hasOwnProperty('sharedProperty') ==
false.Example.localPropertyExample, e.g.
Example.hasOwnProperty('localProperty') ==
true.example.somePropertyexample.hasOwnProperty('localProperty') ==
true.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.
NaNNaN 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));
InfinityInfinity 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));
undefinedundefined 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(…)MathError(…)EvalError(…)RangeError(…)ReferenceError(…)SyntaxError(…)TypeError(…)URIError(…)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.prototypeObject.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.constructorcontains 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.isEnumerable(property)returns true if property is
enumerated during a for (p in instance)
loop.
Mozilla and MSIE do not support
isEnumerable.
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.nameMozilla 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.lengthObject 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;
}
// 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.isEnumerable ' + object.isEnumerable);
// 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 ('isEnumerable' in object)
{
msg('object.property1 is enumerable ' +
object.isEnumerable('property1'));
msg('object.constructor is enumerable ' +
object.isEnumerable('constructor'));
}
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.prototypeFunction.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.constructorreturns 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.lengthreturns 1
msg('Function.length == ' + Function.length);
.lengthReturns 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.
.arityA 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);
.prototypeThe prototype property of function
instances is used as the prototype object for objects
created from using the function as a
constructor.
.nameMozilla 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 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.prototypeArray.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.constructorReturns 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.lengthReturns 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);
StringString 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.prototypeString.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.constructorReturn 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));
[] 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:
-1this compares less than
that+1this compares greater than
that0this and that compare as
equalString.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.
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.
["A", undefined, "B", "bold", "/", "B", "and", undefined, "CODE", "coded", "/", "CODE", ""]
["A", "", "B", "bold", "/", "B", "and", "", "CODE", "coded", "/", "CODE", ""]
["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.lengthlength 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 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.prototypeBoolean.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.constructorReturns 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(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.prototypeNumber.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.constructorReturns 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_VALUEReturns the maximum value of a number representable in JavaScript.
msg('Number.MAX_VALUE == ' + Number.MAX_VALUE);
Number.MIN_VALUEReturns the minimum value of a number representable in JavaScript.
msg('Number.MIN_VALUE == ' + Number.MIN_VALUE);
Number.NaNReturns the same value as the global property
NaN.
Number.NEGATIVE_INFINITYReturns -Infinity
msg('Number.NEGATIVE_INFINITY == ' + Number.NEGATIVE_INFINITY);
Number.POSITIVE_INFINITYReturns +Infinity
msg('Number.POSITIVE_INFINITY == ' + Number.POSITIVE_INFINITY);
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.EThe 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.LN10The 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.LN2The 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.LOG2EThe 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.LOG10EThe 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.PIThe value for Π.
msg('Math.PI == ' + Math.PI);
Math.SQRT1_2The 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.SQRT2The 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 [, …]]])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.
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.
0 to
99, it is treated as year
+ 99 otherwise is it treated as the full year of
the date.0
(January) to 11 (December).1 to the number of days in the month0 to
23.0 to
59.0 to
59.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.prototypeDate.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.constructorReturns 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.
Thu Jul 04 1776 12:30:00 GMT-0500 (Eastern Standard Time)
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.
12:30:00 GMT-0500 (Eastern Standard Time)
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.
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.
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/foo./foo/gfoo./foo/ifoo
ignoring the case of the letters./foo$/mfoo
which is followed by a newline character or the end of the
string.\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 \\.
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.
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.
\dMatches 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);
\DMatches 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);
\fMatches 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);
\nMatches 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);
\rMatches 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);
\sMatches 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.
\SMatches 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.
\tMatches a tab.
\vMatches 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.
\wMatches any word character consisting of a letter, number, underscore or digit.
\WMatches any non-word character.
\0Matches the NUL character.
\xHHMatches the character whose hexadecimal
character code is 0xHH.
where H is a hexadecimal digit.
\uHHHHMatches the character whose unicode character
code is \uHHHH. where
H is a hexadecimal digit.
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);
XYXY 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|YX|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"));
(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"));
\NWhen 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)
RegExp and
flags is defined, then a
TypeError will be thrown.undefined,
pattern is treated as the empty string
otherwise pattern is converted to a
string.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.prototypeRegExp.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.constructorReturns 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);
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))/
captures[0] item will
contain the substring which matched the entire
pattern.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.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.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.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.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.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 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 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());
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.
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.indexread 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.$_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.lastIndexRegExp.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['$&']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['$+']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.$`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.$'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.$9RegExp.$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.sourceReturns 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.globalRead 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.ignoreCaseRead 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.multilineRead 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.lastIndexIf 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 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.
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.prototypeError.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.constructorReturns a reference to the Error
constructor.
Error.prototype.nameError.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.messageError.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.stackerror.lineNumberMozilla provides additional properties on
Error objects:
stackstack 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).
/*
* 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();
EvalErrorMozilla and MSIE do not throw EvalError
for indirect uses of eval or assignments
to eval which is allowed by ECMAScript 16. Errors.
RangeErrorThrown 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.
ReferenceErrorMSIE 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 );
}
SyntaxErrorA 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
);
}
TypeErrorA 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
);
}
URIErrorA 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);
}