Introduction to JavaScript

Overview

JavaScript, the language, is

Some links:

Getting Started

Here's your first Javascript program (a one-liner, of course):

alert("Hello, world.");

This program (a.k.a. script) consists of
one statement which is a call to
the function that is the value of
the property named alert of
the global object.

There are at least four ways to run JavaScript code:

  1. Type "javascript:" followed by the program into your web browser's location field.
  2. Use the JavaScript Runner.
  3. Use the JavaScript Shell.
  4. Embed the script inside an HTML or XHTML document and load the document into a browser:
    <html>
      <head>
        <title>A Greeting</title>
      </head>
      <body>
        <p>My first JavaScript program:</p>
        <script>
          alert("Hello, World.");
        </script>
      </body>
    </html>
    

JavaScript programs can run not only in web browsers, but also virtual worlds, Adobe Photoshop, and other environments. When running inside a web browser, your scripts have access to windows, menus, pop-ups, dialog boxes, textareas, anchors, frames, histories, cookies and other objects.

Exercise: What other host environments have JavaScript programs run in?

Here's more complicated program. Try it in the runner, the shell, or inside an XHTML document.

// A script with two functions and code to exercise them

var today = function () {
    return new Date();
};

var cubed = function (x) {
    return x * x * x;
};

var n = 10;
document.write("<b>Some cubes for " + today() + "</b>");
for (var i = 0; i < n; i += 1) {
    document.write("<br />" + cubed(i));
}

Basic Concepts

The language architecture is rather simple:

That's it. Things that seem like basic concepts, like functions, arrays, and regular expressions are just kinds of objects, though syntactically sugared.

The ECMAScript language standard defines a core set of types, values, objects, properties and functions. A conforming implementation may add extra types, values, objects, properties and functions. JavaScript 1.5 conforms to ECMA-262, edition 3.

If you come from the C, C++, Java, Ada world where compilers seem to check everything, remember Javascript is a dynamic language like Perl, Python, PHP, PostScript, Smalltalk, Self, etc:

Data Types

There are 6 types

TypeValues of the Type
Undefined Only one value: undefined.
null Only one value: null.
Boolean Only two values: true and false.
Number The IEEE 754 floating point values, expressible in decimal or hex. (JavaScript also supports octal literals but ECMA-262 ed. 3 does not.) Examples:
  • 8
  • 7.23342
  • 6.02e23
  • 0xff
  • Infinity
  • NaN
String Quote-delimited strings of zero or more UTF-16 code units. Examples:
  • "hello"
  • "She said 'nyet'"
  • 'x = "4"'
  • "abc\tdef\"\r\nghi"
  • "Olé"
  • "Ol\xe9"
  • 'Will I?\u043d\u0435\u0442\u263a'
(Strings are immutable, and can be operated on with ==, !=, <, <=, >=, >, and +.)
Object Everything that isn't one of the above five types.

The first five above are called primitive types, and their values can be stored directly. Object values are always accessed through references.

Type Coercion

JavaScript is pretty loose with types, when expressions don't have the expected type JavaScript will often compute a derived expression that does.

Examples:

Complete details are in Section 9 of the ECMAScript Standard.

Exercise: Find out what happens when a number is expected but a non-number is given.

Statements

A program is a sequence of statements and function declarations. The kinds of statements are:

Objects

Objects have properties. Access the properties with either dot or square bracket notation. Note: You don't make a class and declare the properties; you just start using them. You can even delete properties.

var x = {};
x.age = 17;
x.height = 65.3;
var score = x.age * x["height"];
var z = {age: 30, color: "red", total: 3};
z.last = true;
var rat = {triple: {a:4, b:undefined, c:{4:null}}, 7: "stuff"};
delete z.age;

jsobjects.png

Arrays

An array is a kind of object with "numeric properties." Fortunately JavaScript provides a convenient syntax for them, too:

var a = [];
var b = [1, 5, 25];
var c = new Array();        // Lame way to say []
var d = new Array{4, 5, 6); // Lame way to say [4, 5, 6]
var e = new Array(10);      // 10 cells, all undefined.
var f = a.length;
var g = [1, true, [1,2], {x:5, y:6}, "Hi"];
var h = {triple: {a:4, b:"dog", c:[1,null]}, 7: "stuff"};
var i = [h.triple.a, h[7]];

alert(g[1]);      // Alerts true.
alert(g[2][0]);   // Alerts 1.
alert(g.length);  // Alerts 5.
g[10] = 100;      // Makes g[5] through g[9] undefined.
alert(g.length);  // Alerts 11.
g.length = 2;     // Now g is just [1, true].
Exercise: Experiment with arrays. Can we get to the third element of array dogs by saying dogs.2 or dogs["2"]? Or is dogs[2] the only way? What about dogs."2" or var x=2; dogs.x?
Exercise: Experiment some more with arrays. Does var x = ["dog"] define a one element array? What if we create a three-element array and try to print the value of its 12th element? What if we create a three-element array and set the value of its 12th element.
Exercise: What's going on here?
   var a = new Array(3);
   a[0] = 1;
   a[1] = "hello";
   a[2] = a;

Functions

You can define a function three ways

function successor (x) {
    return x + 1;
}

var sum = function (x,y) {return x + y;}

var predecessor = new Function("x", "return x - 1;");

The latter two make it clear that a function is just an object. The third one, though interesting, is very slow (why?) and considered evil.

Because a function is an object,

Examples:

function plusSix (x) {return x + 6;}
function squared (x) {return x * x;}
function twice (f, x) {return f(f(x));}
document.write(twice(plusSix, 5) + " ");
document.write(twice(squared, 4) + " ");
function compose (f, g) {return function(x) {return g(f(x));}}
var squareThenPlusSix = compose(squared, plusSix);
document.write(squareThenPlusSix(10) + " ");
document.write(compose(plusSix, squared)(5) + " ");
document.write("twice expects " + twice.length + " arguments");

this

If you call a function that is a property of an object, within that function the expression this refers to the containing object.

var x = {a:1, b:function(x) {return x + this.a;}};
document.write(x.b(2));

will write 3.

The expression this is evaluated dynamically, not statically:

function f(x) {return x + this.a;}
var x = {a:10, b:f};
document.write(x.b(2));

will write 12. This is starting to look useful...

var p = {
    x: 0,
    y: 0,
    move: function(dx, dy) {this.x += dx; this.y += dy;},
    reflect: function() {this.x = -this.x; this.y = -this.y;}
};
p.move(5, 4);
p.reflect();
document.write(p.x + " " + p.y);

This made something that looks like a point object. What if we want a whole bunch of points?

Constructors

Check this out:

function Point() {
    this.x = 0;
    this.y = 0;
    this.move = function(dx, dy) {this.x += dx; this.y += dy;}
    this.reflect = function() {this.x = -this.x; this.y = -this.y;}
    return this;
};

var p = new Point();   // The 'new' is crucial!
p.move(52, 40);
p.reflect();
document.write(p.x + " " + p.y);

When you call the function with new, the function you call behaves as a constructor which means:

That constructor we just wrote isn't very good because

One way (but perhaps not the best way) to fix this is to add global functions (ugh) and assign these to the method properties:

function point_move(dx, dy) {this.x += dx; this.y += dy;}
function point_reflect() {this.x = -this.x; this.y = -this.y;}
function point_to_string() {return "(" + this.x + "," + this.y + ")";}

function Point(x, y) {
    this.x = x || 0;
    this.y = y || 0;
    this.move = point_move;
    this.reflect = point_reflect;
    this.toString = point_to_string;
};

var p = new Point();
var q = new Point(3, 7);
p.move(52, 40);
p.reflect();
q.move(1, 1)
document.write(p + " " + q);
Exercise: Explain the "|| 0" idiom.

Prototypes

Now suppose you wanted to add a "move_to_origin" method. You could add it to just one object:

    p.moveToOrigin = function() {this.x = 0; this.y = 0;}
    p.moveToOrigin();
    q.moveToOrigin(); // ERROR: q has no moveToOrigin property
    document.write(p + " " + q);

But to add it to every point object, even those not yet created, you can rewrite the constructor, or add the method to the prototype of any existing point object.

    Point.prototype.moveToOrigin = function() {this.x = 0; this.y = 0;}
    p.moveToOrigin();
    q.moveToOrigin();
    document.write(p + " " + q);

Hey! This looks like a better way to do methods. We don't have to pollute the global namespace:

function Point(x, y) {
    this.x = x || 0;
    this.y = y || 0;
};
Point.prototype.move = function(dx, dy) {this.x += dx; this.y += dy;}
Point.prototype.reflect = function() {this.x = -this.x; this.y = -this.y;}
Point.prototype.toString = function() {return "(" + this.x + "," + this.y + ")";}

var q = new Point(3, 7);

This works because If you try to access (read the value of or call), say, x.p and x doesn't have property p, JavaScript will (recursively) look for p in x.__proto__. (And remember the value of x.__proto__ is set to the value of y.prototype where y is the constructor that constructed x.)

Important Exercise: We just saw that the prototype chain is searched when we try to read a property from an object that doesn't have the property. But what happens if you try to write a property that doesn't exist in an object, but does exist in an object higher in the prototype chain?

Any object can have a prototype, but prototypes are most useful on constructor functions.

Inheritance

You can make deep "class hierarchies" once you are comfortable with prototype chains, but if you find yourself doing this frequently, or making particularly deep hierarchies, ask yourself why you are using JavaScript.

One way to wing this, using a classic (pun intended) example:

function Person(name, birthday) {
    this.name = name || "Unknown"
    this.birthday = birthday;
}

Person.prototype.age = function() {
    return new Date().getTime() - this.birthday.getTime();
}

function Employee(name, birthday, id) {
    Person.apply(this, [name, birthday]);
    this.id = id;
}
Employee.prototype = new Person();

function Student(name, birthday, gpa) {
    Person.apply(this, [name, birthday]);
    this.gpa = gpa;
}
Student.prototype = new Person();

function Administrator(name, birthday, id) {
    Employee.apply(this, [name, birthday, id]);
}
Administrator.prototype = new Employee();

function Instructor(name, birthday, id, department) {
    Employee.apply(this, [name, birthday, id]);
    this.department = department;
}
Instructor.prototype = new Employee();

One problem with this approach is the prototypes lose their constructor property, which hurts you if you are trying to do something like Java's getClass() with it. You have to fall back to using instanceof; Object.prototype.toString.call() won't work for things you define. Or go ahead and hack the constructor property back in!! Why are we doing this again???

If you still want to do this kind of stuff, Douglas Crockford has a page showing several different ways to do it. He concludes that "Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies. Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive." Good advice. Use JavaScript's dynamic features; don't let your thinking get mired in the rigidity of static classes.

Lexical Matters

JavaScript

Reserved Words

Reserved words currently being used

    break      else       instanceof   true
    case       false      new          try
    catch      finally    null         typeof
    continue   for        return       var
    default    function   switch       void
    delete     if         this         while
    do         in         throw        with

Reserved words without any use today

    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

Identifiers

Syntax of identifiers

String Literal Escapes

Escape SequenceCode Point (in Hex)Character Name
\b 8 Backspace
\t 9 Horizontal Tab
\n A Line Feed
\v B Vertical Tab
\f C Form Feed
\r D Carraige Return
\" 22 Double Quote
\' 27 Single Quote
\\ 5C Backslash
\xh1h2
(two hex digits)
10 * h1 + h2 -
\uh1h2h3h4
(four hex digits)
1000 * h1 + 100 * h2 + 10 * h3 + h4 -

Operators

From highest to lowest precedence

Operators Associativity Description
.
[]
L member (rhs cannot start with a digit)
member
()
new
N/A call
create instance
++
--
N/A postfix increment
postfix decrement
!
~
-
+
++
--
typeof
void
delete
R logical not
bitwise not
unary negation
unary plus
prefix increment
prefix decrement
type name
eval and return undefined
delete
*
/
%
L multiply
divide
modulo
+
-
L add
subtract
<<
>>
>>>
L left shift
arithmetic right shift (sign fill)
logical right shift (zero fill)
<
<=
>
>=
in
instanceof
L less than
less than or equal
greater than
greater than or equal
has property
has type
==
!=
===
!==
L equals
not ==
equals and same type
not ===
& L bitwise-and
^ L bitwise xor
| L bitwise or
&& L short-circuit logical and
|| L short-circuit logical or
?: R conditional
=
+= -=
*= /= %=
<<= >>= >>>=
&= ^= |=
R assignment
, L comma

Good to know:

Built-in Objects

Entities in bold are specific to JavaScript 1.5 and not ECMA-262.

Name Properties __proto__ Notes
Global NaN Infinity undefined Math eval() parseInt() parseFloat() isNaN() isFinite() decodeURI() decodeURIComponent() encodeURI() encodeURIComponent() Object() Function() Array() String() Boolean() Number() Date() RegExp() Error() EvalError() RangeError() ReferenceError() SyntaxError() TypeError() URIError() [implementation dependent] Not directly accessible
Object length prototype Function.prototype
Object.prototype constructor toString() toLocaleString() valueOf() hasOwnProperty() isPrototypeOf() propertyIsEnumerable() toSource() watch() unwatch() null
Function length prototype Function.prototype instance properties: length prototype
Function.prototype constructor arity caller toString() apply() call() Object.prototype
Array length prototype Function.prototype instance properties: length
Array.prototype constructor index input concat() join() pop() push() reverse() shift() slice() splice() sort() unshift() every() some() filter() forEach() map() indexOf() lastIndexOf() Object.prototype
String length prototype fromCharCode() Function.prototype instance properties: length
String.prototype constructor toString() valueOf() charAt() charCodeAt() indexOf() lastIndexOf() localeCompare() match() concat() split() splice() slice() substring() replace() search() toLowerCase() toLocaleLowerCase() toUpperCase() toLocaleUpperCase() (plush a bunch of crap methods that write out crappy HTML — don't use that crap) Object.prototype
Boolean length prototype Function.prototype
Boolean.prototype constructor toString() valueOf() Object.prototype
Number length prototype MAX_VALUE MIN_VALUE NaN NEGATIVE_INFINITY POSITIVE_INFINITY Function.prototype
Number.prototype constructor toString() toLocaleString() valueOf() toFixed() toPrecision() toExponential() Object.prototype
Math E PI SQRT_2 SQRT1_2 LN2 LN10 LOG2E LOG10E abs() sin() cos() tan() acos() asin() atan() atan2() exp() log() ceil() floor() min() max() pow() random() round() sqrt() Object.prototype
Date length prototype parse() UTC() Function.prototype
Date.prototoype constructor toString() toDateString() toTimeString() toLocaleString() toLocaleDateString() toLocaleTimeString() valueOf() getTime() getFullYear() getUTCFullYear() getMonth() getUTCMonth() getDate() getUTCDate() getDay() getUTCDay() getHours() getUTCHours() getMinutes() getUTCMinutes() getSeconds() getUTCSeconds() getMilliseconds() getUTCMilliseconds() getTimezoneOffset() setTime() setMilliseconds() setUTCMilliseconds() setSeconds() setUTCSeconds() setMinutes() setUTCMinutes() setHours() setUTCHours() setDate() setUTCDate() setMonth() setUTCMonth() setFullYear() setUTCFullYear() toUTCString() getYear() setYear() getUTCYear() setUTCYear() toGMTString() Object.prototype
RegExp length prototype Function.prototype instance properties: source global ignoreCase multiline lastIndex
RegExp.prototype constructor exec() test() toString() Object.prototype
Error length prototype Function.prototype
Error.prototype constructor name message toString() Object.prototype
EvalError length prototype Function.prototype
EvalError.prototype constructor name message() Error.prototype
RangeError length prototype Function.prototype
RangeError.prototype constructor name message() Error.prototype
ReferenceError length prototype Function.prototype
ReferenceError.prototype constructor name message() Error.prototype
SyntaxError length prototype Function.prototype
SyntaxError.prototype constructor name message() Error.prototype
TypeError length prototype Function.prototype
TypeError.prototype constructor name message() Error.prototype
URIError length prototype Function.prototype
URIError.prototype constructor name message() Error.prototype

Other Objects

Host environments provide lots of their own objects. You're likely to see these in most web environments:

Anchor        Applet   Area         Arguments   Button     Checkbox   Crypto
Document      Event    FileUpload   Form        Frame      Hidden     History
HTMLElement   Image    Input        Layer       Link       Location   MimeType
Navigator     Option   Password     Plugin      Radio      Reset      Screen
Select        Style    Submit       Text        TextArea   Window

Miscellany

Regular Expressions

JavaScript has special syntactic sugar for regular expressions, for example

/dog/
/JavaScript/i
/moe|larry|curly/i
/colo(u)?r/
/<([^>]*)>[^<]*<\/\1>/
/\d{5}(-\d{4})?/

JavaScript's regular expression language is pretty "standard":

Important:

Property Attributes

Each property has between zero and four attributes:

AttributeDescription
ReadOnly writes to the property will be ignored
DontEnum property will be skipped in a for-in enumeration
DontDelete deletion attempts will be ignored
Internal not accessible in normal code

Execution Contexts

A couple aspects of JavaScript aren't so easy to explain just by using the notion of objects with properties. Examples:

These things, and others like them, are described in terms of execution contexts in Section 10 of the ECMAScript standard.

Further Study