JavaScript

CSCE 242

University of South Carolina


José M. Vidal [1]
http://jmvidal.cse.sc.edu/talks/javascript/ [2]

An introduction to the language. This talk follows: Examples are taken [5] from Flanagan.

1 Introduction

1.1 Example

This code:
<html>
<head><title>Factorials</title></head>
<body>
<h2>Table of Factorials</h2>
<script>
<!--
var fact = 1;
for(i = 1; i < 10; i++) {
    fact = fact*i;
    document.write(i + "! = " + fact + "<br>");
}
-->
</script>
</body>
</html>
Looks like this.

1.2 Another Example

<html>
<head>
<title>JavaScript Loan Calculator</title>
<style>
.result { font-weight: bold; }  /* For elements with class="result" */
#payment { text-decoration: underline; } /* For element with id="payment" */
</style>
</head>
<body>
<form name="loandata">
  <table>
    <tr><td><b>Enter Loan Information:</b></td></tr>
    <tr>
      <td>1) Amount of the loan (any currency):</td>
      <td><input type="text" name="principal" onchange="calculate();"></td>
    </tr>
    <tr>
      <td>2) Annual percentage rate of interest:</td>
      <td><input type="text" name="interest" onchange="calculate();"></td>
    </tr>
    <tr>
      <td>3) Repayment period in years:</td>
      <td><input type="text" name="years" onchange="calculate();"></td>
    </tr>
    <tr><td></td>
      <td><input type="button" value="Compute" onclick="calculate();"></td>
    </tr>
    <tr><td><b>Payment Information:</b></td></tr>
    <tr>
      <td>4) Your monthly payment:</td>
      <td>$<span class="result" id="payment"></span></td>
    </tr>
    <tr>
      <td>5) Your total payment:</td>
      <td>$<span class="result" id="total"></span></td>
    </tr>
    <tr>
      <td>6) Your total interest payments:</td>
      <td>$<span class="result" id="totalinterest"></span></td>
    </tr>
  </table>
</form>

<script language="JavaScript">
/*
 * This is the JavaScript function that makes the example work. Note that
 * this script defines the calculate() function called by the event
 * handlers in the form. The function reads values from the form
 * <input> fields using the names defined in the HTML code above.  It outputs
 * its results into the named <span> elements.
 */
function calculate() {
    // Get the user's input from the form. Assume it is all valid.
    // Convert interest from a percentage to a decimal, and convert from
    // an annual rate to a monthly rate. Convert payment period in years
    // to the number of monthly payments.
    var principal = document.loandata.principal.value;
    var interest = document.loandata.interest.value / 100 / 12;
    var payments = document.loandata.years.value * 12;

    // Now compute the monthly payment figure, using esoteric math.
    var x = Math.pow(1 + interest, payments);
    var monthly = (principal*x*interest)/(x-1);

    // Get named <span> elements from the form.
    var payment = document.getElementById("payment");
    var total = document.getElementById("total");
    var totalinterest = document.getElementById("totalinterest");

    // Check that the result is a finite number. If so, display the
    // results by setting the HTML content of each <span> element.
    if (isFinite(monthly)) {
        payment.innerHTML = monthly.toFixed(2);
        total.innerHTML = (monthly * payments).toFixed(2);
        totalinterest.innerHTML = ((monthly*payments)-principal).toFixed(2);
    }
    // Otherwise, the user's input was probably invalid, so display nothing.
    else {
        payment.innerHTML = "";
        total.innerHTML = ""
        totalinterest.innerHTML = "";
    }
}
</script>
</body>
</html>

Results in this.

2 Lexical Structure

3 Datatypes and Values

3.1 Numbers

3.1.1 Special Numbers

3.2 Strings

3.2.1 Working with Strings

3.3 Booleans

3.4 Functions

function square(x) {
        return x * x;
}
var square = function (x) {return x*x};
square(5); [22]
var plusone = function (x) {return x+1};
var doublef = function (f,x) {return f(f(x))};
doublef(plusone,5) [23]

3.5 Objects

//The new operator pretends we have Classes

var o = new Object();
var now = new Date();


//Object literals are much faster, aka JSON

var point = {x:2.3, y:-1.2};
var rectangle =
        {
                upperLeft: {x:2,y:2},
                lowerRight: {x:4, y:0}
        };

3.6 Arrays

var a = [1, "hello", true, {x:1, y:2}, 4];
a; [24]

3.7 Date

3.8 Regular Expressions

3.9 Wrapper Objects

//primitive data type
var s = "hello";

//an object.
vas S = new String("hello");

3.10 Value vs Reference

var n = 1;  // Variable n holds the value 1
var m = n;  // Copy by value: variable m holds a distinct value 1

function add_to_total(total, x)
{
    total = total + x;  // This line changes only the internal copy of total
}

add_to_total(n, m);

if (n == 1) m = 2;  // n contains the same value as the literal 1; m is now 2

m; [26]
var xmas = new Date(2007, 11, 25);

var solstice = xmas;  // Both variables now refer to the same object value

solstice.setDate(21);

xmas.getDate();  // Returns 21, not the original value of 25

(xmas == solstice)  // Evaluates to true

// The two variables defined next refer to two distinct objects, both
// of which represent exactly the same date.
var xmas = new Date(2007, 11, 25);
var solstice_plus_4 = new Date(2007, 11, 25);


//totals will be different after function returns
function addToTotals(totals, x)
{
    totals[0] = totals[0] + x;
    totals[1] = totals[1] + x;
    totals[2] = totals[2] + x;
}
var t = [1,2,3];
addToTotals(t,5);
xmas != solstice_plus_4 [27]

t; [28]

4 Variables

var message = "hello";
var i=0, j=0, k=1;

4.1 Scope

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function nested() {
        var scope = "nested scope";
        alert("1-" + scope); //prints, what?
    }
    nested();
    scope = "local scope";
    for (var i =0; i < 10; i++){
        var scope = "nested scope";     
    }
    alert("2-" + scope);
}

checkscope()

4.1.1 var Location Does Not Matter

var scope = "global";
function checkloc() {
        alert ("1-" + scope);
        var scope = "local";
        alert ("2-" + scope);
}
checkloc()

4.2 Variables as Properties

5 Expressions and Operators

5.1 Relational Operators

5.2 String Operators

5.3 delete Operator

var o = {x:1,y:2};

delete o.x;

delete o; 

o;

6 If Statements

if ((a == null) || (b == "")) {
        //do something
 }
 else if (n == 3) {
         //do something else
 }
 else {
         //do something else
 }

6.1 Switch

function convert(x){
        switch(typeof x) {
        case 'number':
                return x.toString(16);
        case 'string':
                return '"' + x + '"';
        case 'boolean':
                return x.toString().toUpperCase();
        default:
                return x.toString();
        }
}

6.2 While

while (count < 10){
        document.write(count + "<br/>");
 }


do {
        document.write(a[i] + "<br/>");
 } while (++i < a.length);

6.3 For

for (i = 0, j = 10; i < 10; i++, j--){
        sum += i * j;
 };

var d = {x:1, y:2};
for (var prop in d){
        alert(prop + ":" + d[prop]);
 }
Run [47]

6.4 Labels and Break

function testbreak(){
 outerloop:
        for (var i = 0; i < 10; i++){
        innerloop:
                for(var j = 0; j< 10; j++){
                        if (j > 3) break;
                        if (i == 2) break innerloop;
                        if (i == 3) break outerloop;
                        alert("i=" + i + " j=" + j);
                }
        }
        alert("Final i=" + i + " j=" + j);
}

testbreak()

6.5 Throw and Catch

function factorial (x) {
        if (x < 0) {
                throw new Error("Negative argument" + x);
        }
        for (var f = 1; x > 1; f *= x, x--);
        return f;
}
try {
        //do stuff
 }
 catch (e) {
         //only one catch, so you might need to:
         switch (e.name) {
         case 'Error':
                 //stuff
                 break;
         default:
                 throw e;
         }
 }
finally {
        //statements that always get executed
}

7 Objects and Arrays

//The new operator pretends we have Classes

var o = new Object();
var now = new Date();


//Object literals are much faster, aka JSON

var point = {x:2.3, y:-1.2};
var rectangle =
        {
                upperLeft: {x:2,y:2},
                lowerRight: {x:4, y:0}
        };

7.1 Object Properties

function DisplayPropertyNames(o){
        var names ="";
        for (var name in o) {
                names += name + " ";
        }
        alert(names);
}
DisplayPropertyNames(document)
//If o has property named "x" then set it
if ("x" in o) {
        o.x = 1;
 }

//If "x" exists and is not undefined, set it
if (o.x !== undefined) {
        o.x = 1;
 }

7.2 Objects as Associative Arrays

object.property
object["property"]

7.3 Universal Properties and Methods

7.4 Arrays

var c = new Circle(1,2,3);
c[0] = "this is an array element of an object";

7.4.1 Array Length

7.4.2 Array Methods

8 Functions

function hypotenuse(a,b){
        function square(x) {
                return x*x;
        }
        return Math.sqrt(square(a) + square(b));
}

8.1 Arguments to Functions

//Copy property names to a.
//If a is missing, create a new a.
function copyPropertyNamesToArray(o, /*optional*/ a){
        if (!a) {
                a = [];
        };
        for (var p in o) {
                a.push(p);
        }
        return a;
}
        
function getArguments(){
        //can't use join() because arguments is an object (that looks like an array).
        var result = "";
        for (var i =0; i< arguments.length; i++){
                result += arguments[i] + " ";
        }
        return result;
}

function getCaller(){
        return arguments.callee;
}

getArguments(1,2,3) [70]

getArguments('hi', 2) [71]

getArguments() [72]

getCaller() [73]

f = function(x) {
        if (x <= 1){
                return 1;
        }
        return x * arguments.callee(x-1);
}

8.2 Functions as Data

// We define some simple functions here
function add(x,y) { return x + y; }
function subtract(x,y) { return x - y; }
function multiply(x,y) { return x * y; }
function divide(x,y) { return x / y; }

// Here's a function that takes one of the above functions
// as an argument and invokes it on two operands
function operate(operator, operand1, operand2)
{
    return operator(operand1, operand2);
}

// We could invoke this function like this to compute the value (2+3) + (4*5):
var i = operate(add, operate(add, 2, 3), operate(multiply, 4, 5));

// For the sake of the example, we implement the functions again, this time
// using function literals within an object literal;
var operators = {
    add:      function(x,y) { return x+y; },
    subtract: function(x,y) { return x-y; },
    multiply: function(x,y) { return x*y; },
    divide:   function(x,y) { return x/y; },
    pow:      Math.pow  // Works for predefined functions too
};

// This function takes the name of an operator, looks up that operator
// in the array, and then invokes it on the supplied operands. Note
// the syntax used to invoke the operator function.
function operate2(op_name, operand1, operand2)
{
    if (typeof operators[op_name] == "function")
        return operators[op_name](operand1, operand2);
    else throw "unknown operator";
}

// We could invoke this function as follows to compute
// the value ("hello" + " " + "world"):
var j = operate2("add", "hello", operate2("add", " ", "world"))
// Using the predefined Math.pow() function:
var k = operate2("pow", 10, 2)
i; [74]

j; [75]

k; [76]

8.3 Functions as Methods

var calculator = {
        operand1: 1,
        operand2: 3,
        compute: function () {
                this.result = this.operand1 + this.operand2;
        }
};
calculator.compute(); [77]

calculator.result [78]

8.4 Function Properties

function foo(x,y,z){};
foo.length
[79]

8.4.1 Defining new Function Properties

getuid.id=0;

function getuid() {
        return getuid.id++;
}
getuid() [80]

8.4.2 apply and call

8.4.3 Utility Function Examples

// Return an array that holds the names of the enumerable properties of o
function getPropertyNames(/* object */o) {
    var r = [];
    for(name in o) r.push(name);
    return r;
}

// Copy the enumerable properties of the object from to the object to.
// If to is null, a new object is created.  The function returns to or the
// newly created object.
function copyProperties(/* object */ from, /* optional object */ to) {
    if (!to) to = {};
    for(p in from) to[p] = from[p];
    return to;
}

// Copy the enumerable properties of the object from to the object to,
// but only the ones that are not already defined by to.
// This is useful, for example, when from contains default values that
// we want to use if they are not already defined in to.
function copyUndefinedProperties(/* object */ from, /* object */ to) {
    for(p in from) {
        if (!p in to) to[p] = from[p];
    }
}

// Pass each element of the array a to the specified predicate function.
// Return an array that holds the elements for which the predicate
// returned true
function filterArray(/* array */ a, /* boolean function */ predicate) {
    var results = [];
    var length = a.length;  // In case predicate changes the length!
    for(var i = 0; i < length; i++) {
        var element = a[i];
        if (predicate(element)) results.push(element);
    }
    return results;
}

// Return the array of values that result when each of the elements
// of the array a are passed to the function f
function mapArray(/* array */a, /* function */ f) {
    var r = [];             // to hold the results
    var length = a.length;  // In case f changes the length!
    for(var i = 0; i < length; i++) r[i] = f(a[i]);
    return r;
}

// Return a standalone function that invokes the function f as a method of
// the object o.  This is useful when you need to pass a method to a function.
// If you don't bind it to its object, the association will be lost and
// the method you passed will be invoked as a regular function.
function bindMethod(/* object */ o, /* function */ f) {
    return function() { return f.apply(o, arguments) }
}

// Return a function that invokes the function f with the
// specified arguments and also any additional arguments that are
// passed to the returned function. (This is sometimes called "currying".)
function bindArguments(/* function */ f /*, initial arguments... */) {
    var boundArgs = arguments;
    return function() {
        // Build up an array of arguments.  It starts with the previously
        // bound arguments and is extended with the arguments passed now
        var args = [];
        for(var i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]);
        for(var i = 0; i < arguments.length; i++) args.push(arguments[i]);
        
        // Now invoke the function with these arguments
        return f.apply(this, args);
    }
}

8.5 Scoping

function hypotenuse(a,b){
        function squarea() {
                return a*a;
        }
        function squareb() {
                return b*b;
        }
        return Math.sqrt(squarea() + squareb());
}
hypotenuse(2,2); [81]

8.5.1 Call Object as Namespace

(function () { //anonymous function
        var a = 123; //this variable will dissapear at the end of the function
        var b = 'hello';
        //some more code here
 })(); //invoke my anonymous function

8.5.2 Closures

var x = "global";
function f() {
    var x = "local";
    function g() { //creates a closure
        alert(x);
    };
    return g();
}
x; [82]

f(); [83]

var x = "global";
function f2() {
        var x = "local";
        function g() { //creates a closure
                alert(x);
        };
        return g;
}
var g = f2();
x; [84]

g(); [85]

function makefunc(x) {
        return function() {
                return x;
        }
}

var a = [makefunc(0), makefunc(1), makefunc(2)];

a[0](); [86]

a[1](); [87]

a[2](); [88]

8.5.3 Sharing Closure Variables Among Functions

//
// This function adds property accessor methods for a property with 
// the specified name to the object o.  The methods are named get<name>
// and set<name>.  If a predicate function is supplied, the setter
// method uses it to test its argument for validity before storing it.
// If the predicate returns false, the setter method throws an exception.
// 
// The unusual thing about this function is that the property value 
// that is manipulated by the getter and setter methods is not stored in
// the object o.  Instead, the value is stored only in a local variable
// in this function.  The getter and setter methods are also defined
// locally to this function and therefore have access to this local variable.
// Note that the value is private to the two accessor methods, and it cannot
// be set or modified except through the setter.
// 
function makeProperty(o, name, predicate) {
    var value;  // This is the property value

    // The setter method simply returns the value
    o["get" + name] = function() { return value; };

    // The getter method stores the value or throws an exception if
    // the predicate rejects the value
    o["set" + name] = function(v) { 
        if (predicate && !predicate(v))
            throw "set" + name + ": invalid value " + v;        
        else
            value = v;
    };
}

// The following code demonstrates the makeProperty() method 
var o = {};  // Here is an empty object

// Add property accessor methods getName and setName()
// Ensure that only string values are allowed
makeProperty(o, "Name", function(x) { return typeof x == "string"; });

o.setName("Frank");  // Set the property value

o.getName() [89]

o.setName(123) [90]

o.getName() [91]

o.setName('Joe') [92]

o.getName() [93]

8.5.4 Breakpoints using Closures

// 
// This function implements a breakpoint. It repeatedly prompts the user
// for an expression, evaluates it with the supplied self-inspecting closure,
// and displays the result.  It is the closure that provides access to the
// scope to be inspected, so each function must supply its own closure.
// 
// Inspired by Steve Yen's breakpoint() function at
// http://trimpath.com/project/wiki/TrimBreakpoint
//
function inspect(inspector, title) {
    var expression, result;

    // You can use a breakpoint to turn off subsequent breakpoints by
    // creating a property named "ignore" on this function.
    if ("ignore" in arguments.callee) return;

    while(true) {
        // Figure out how to prompt the user
        var message = "";
        // If we were given a title, display that first
        if (title) message = title + "\n";
        // If we've already evaluated an expression, display it and its value
        if (expression) message += "\n" + expression + " ==> " + result + "\n";
        else expression = "";
        // We always display at least a basic prompt:
        message += "Enter an expression to evaluate:";

        // Get the user's input, displaying our prompt and using the
        // last expression as the default value this time.
        expression = prompt(message, expression);

        // If the user didn't enter anything (or clicked Cancel),
        // they're done and so we return, ending the breakpoint.
        if (!expression) return;

        // Otherwise, use the supplied closure to evaluate the expression
        // in the scope that is being inspected. 
        // The result will be displayed on the next iteration.
        result = inspector(expression);
    }
}

function factorial(n) {
        var inspector = function(x) {
                return eval(x);
        }
        inspect (inspector, "Entering factorial()");
        var result = 1;
        while (n > 1){
                result = result * n;
                n--;
                inspect(inspector, "factorial() loop");
        }

        inspect(inspector, "Exiting factorial()");
        return result;
}
inspect(function (x) {return eval(x);}, 'Hello') [94]

factorial(5); [95]

8.5.5 Function Constructor

var f = new Function("x", "y", "return x*y");

//same as this
function f(x,y){
        return x*y;
}

9 Object-Oriented JavaScript

function Rectangle(w, h){
        this.width = w;
        this.height = h;
}

var r1 = new Rectangle(2,3);
r1 [97]

9.1 Prototype

function Rectangle(w, h){
        this.width = w;
        this.height = h;
}

Rectangle.prototype.area = function() {
        return this.width * this.height;
}
        
var r1 = new Rectangle(2,3);
r1.area() [98]

9.1.1 Inheritance Example

//Create a new object which inherits from o.
function object(o) {
    function F() {};
    F.prototype = o;
    return new F();
}

var human = {
    name: "Floyd",
    age: 33,
    sex: "Male",
}

var employee = object(human);

employee.salary = 100;
employee.name; [99]

human.name = 'Pink'; [100]

employee.name; [101]

employee.name = 'Blue'; [102]

human.name; [103]

9.1.2 Inheritance via Constructor Chaining

// Here is a simple Rectangle class.
// It has a width and height and can compute its own area
function Rectangle(w, h) {
    this.width = w;
    this.height = h;
}
Rectangle.prototype.area = function() { return this.width * this.height; }

// Here is how we might subclass it 

function PositionedRectangle(x, y, w, h) {
    // First, invoke the superclass constructor on the new object
    // so that it can initialize the width and height.
    // We use the call method so that we invoke the constructor as a
    // method of the object to be initialized. 
    // This is called constructor chaining.
    Rectangle.call(this, w, h);

    // Now store the position of the upper-left corner of the rectangle
    this.x = x;
    this.y = y;
}

// If we use the default prototype object that is created when we
// define the PositionedRectangle() constructor, we'd get a subclass of Object.
// To subclass, rectangle, we must explicitly create our prototype object.
PositionedRectangle.prototype = new Rectangle();

// We create this prototype object for inheritance purposes, but we
// don't actually want to inherit the width and height properties that
// each Rectangle object has, so delete them from the prototype.
delete PositionedRectangle.prototype.width;
delete PositionedRectangle.prototype.height;

// Since the prototype object was created with the Rectangle() constructor,
// it has a constructor property that refers to that constructor.  But
// we want PositionedRectangle objects to have a different constructor
// property, so we've got to reassign this default constructor property.
PositionedRectangle.prototype.constructor = PositionedRectangle;

// Now that we've configured the prototype object for our subclass,
// we can add instance methods to it.
PositionedRectangle.prototype.contains = function(x,y) {
    return (x > this.x && x < this.x + this.width &&
            y > this.y && y < this.y + this.height);

9.1.3 Extend a Type

String.prototype.trim = function() {
        return this.replace(
         /^\s*(\S*(\s+\S+)*)\s*$/, "$1");
}
                                                                                 
'---' + ' hello there '.trim() + '---' [104]

String.prototype.supplant = function (o){
    return this.replace(/{([^{}]*)}/g,
                        function (a,b) {
                            return o[b];
                        }
                       );
};

var template = '<table border="{border}"' +
        '<tr><th>Last</th><td>{last}</td></tr>' +
        '<tr><th>First</th><td>{first}</td></tr>' +
        '</table>';

var data = {
        first: "Carl",
        last: "Hollywood",
        border: 2
};

template.supplant(data) [105]

9.1.4 Calling Overridden Methods

Rectangle.prototype.toString = function () {
    return "[" + this.width + "," + this.height + "]";
}

PositionedRectangle.prototype.toString = function (){
    return "(" + this.x + "," + this.y +") " +
        Rectangle.prototype.toString.apply(this); //call superclass toString
}

9.1.5 Mixins

// Borrow methods from one class for use by another.
// The arguments should be the constructor functions for the classes
// Methods of built-in types such as Object, Array, Date and RegExp are
// not enumerable and cannot be borrowed with this method.
function borrowMethods(borrowFrom, addTo) {
    var from = borrowFrom.prototype;  // prototype object to borrow from
    var to = addTo.prototype;         // prototype object to extend

    for(m in from) {  // Loop through all properties of the prototye
        if (typeof from[m] != "function") continue; // ignore nonfunctions
        to[m] = from[m];  // borrow the method
    }
}
// This class isn't good for much on its own. But it does define a
// generic toString() method that may be of interest to other classes.
function GenericToString() {}
GenericToString.prototype.toString = function() {
    var props = [];
    for(var name in this) {
        if (!this.hasOwnProperty(name)) continue;
        var value = this[name];
        var s = name + ":" 
        switch(typeof value) {
        case 'function':
            s += "function";
            break;
        case 'object':
            if (value instanceof Array) s += "array"
            else s += value.toString();
            break;
        default:
            s += String(value);
            break;
        }
        props.push(s);
    }
    return "{" + props.join(", ") + "}";
}

// This mixin class defines an equals() method that can compare
// simple objects for equality.
function GenericEquals() {}
GenericEquals.prototype.equals = function(that) {
    if (this == that) return true;
    
    // this and that are equal only if this has all the properties of 
    // that and doesn't have any additional properties
    // Note that we don't do deep comparison.  Property values
    // must be === to each other.  So properties that refer to objects
    // must refer to the same object, not objects that are equals()
    var propsInThat = 0;
    for(var name in that) {
        propsInThat++;
        if (this[name] !== that[name]) return false;
    }

    // Now make sure that this object doesn't have additional props
    var propsInThis = 0;
    for(name in this) propsInThis++;
    
    // If this has additional properties then they are not equal
    if (propsInThis != propsInThat) return false;

    // The two objects appear to be equal.
    return true;
}

borrowMethods(GenericEquals, Rectangle);
borrowMethods(GenericToString, Rectangle)

9.1.6 Complex Numbers Example

/*
 * Complex.js:
 * This file defines a Complex class to represent complex numbers.
 * Recall that a complex number is the sum of a real number and an
 * imaginary number and that the imaginary number i is the
 * square root of -1.
 */

/*
 * The first step in defining a class is defining the constructor
 * function of the class. This constructor should initialize any
 * instance properties of the object. These are the essential
 * "state variables" that make each instance of the class different.
 */
function Complex(real, imaginary) {
    this.x = real;       // The real part of the number
    this.y = imaginary;  // The imaginary part of the number
}

/*
 * The second step in defining a class is defining its instance
 * methods (and possibly other properties) in the prototype object
 * of the constructor. Any properties defined in this object will
 * be inherited by all instances of the class. Note that instance
 * methods operate implicitly on the this keyword. For many methods,
 * no other arguments are needed.
 */

// Return the magnitude of a complex number. This is defined
// as its distance from the origin (0,0) of the complex plane.
Complex.prototype.magnitude = function() {
    return Math.sqrt(this.x*this.x + this.y*this.y);
};

// Return a complex number that is the negative of this one.
Complex.prototype.negative = function() {
    return new Complex(-this.x, -this.y);
};

// Add a complex number to this one and return the sum in a new object.
Complex.prototype.add = function(that) {
    return new Complex(this.x + that.x, this.y + that.y);
}

// Multiply this complex number by another and return the product as a
// new Complex object.
Complex.prototype.multiply = function(that) {
    return new Complex(this.x * that.x - this.y * that.y,
                       this.x * that.y + this.y * that.x);
}

// Convert a Complex object to a string in a useful way.
// This is invoked when a Complex object is used as a string.
Complex.prototype.toString = function() {
    return "{" + this.x + "," + this.y + "}";
};

// Test whether this Complex object has the same value as another.
Complex.prototype.equals = function(that) {
    return this.x == that.x && this.y == that.y;
}

// Return the real portion of a complex number. This function
// is invoked when a Complex object is treated as a primitive value.
Complex.prototype.valueOf = function() { return this.x; }

/*
 * The third step in defining a class is to define class methods,
 * constants, and any needed class properties as properties of the
 * constructor function itself (instead of as properties of the
 * prototype object of the constructor). Note that class methods
 * do not use the this keyword: they operate only on their arguments.
 */
// Add two complex numbers and return the result.
// Contrast this with the instance method add()
Complex.sum = function (a, b) {
    return new Complex(a.x + b.x, a.y + b.y);
};

// Multiply two complex numbers and return the product.
// Contrast with the instance method multiply()
Complex.product = function(a, b) {
    return new Complex(a.x * b.x - a.y * b.y,
                       a.x * b.y + a.y * b.x);
};

// Here are some useful predefined complex numbers.
// They are defined as class properties, and their names are in uppercase
// to indicate that they are intended to be constants (although it is not
// possible to make JavaScript properties read-only).
Complex.ZERO = new Complex(0,0);
Complex.ONE = new Complex(1,0);
Complex.I = new Complex(0,1);

9.1.7 Private Members

//The values of w and h can never be changed after the object is created.
//Constructor:
function ImmutableRectangle (w, h){
    this.getWidth = function() {
        return w;
    };
    this.getHeight = function() {
        return h;
    };
}

//Get values like this.
ImmutableRectangle.prototype.area() = function (){
    return this.getWidth() * this.getHeight();
}

9.2 Common Methods: toString

Circle.prototype.toString = function (){
    return "[Circle of radius " + this.r + ", centered at("
        + this.x + ", " + this.y + ").]";
}

9.3 instanceof

if (x instanceof Array) {
        //something
 }

10 Modules and Namespaces

//Store all my libraries under the directory/namespace jmvidal.
var jmvidal; 
if (!jmvidal) jmvidal = {};
//define my Lib590 library
jmvidal.Lib590 = {};
jmvidal.Lib590.myfun1 = function (x) {
        //code here
};
jmvidal.Lib590.myfun2 = function (x) {
        //code here
}

11 Regular Expressions

URLs

  1. José M. Vidal, http://jmvidal.cse.sc.edu
  2. http://jmvidal.cse.sc.edu/talks/javascript/, http://jmvidal.cse.sc.edu/talks/javascript/
  3. JavaScript, http://jmvidal.cse.sc.edu/lib/flanagan06a.html
  4. JavaScript: The Good Parts, http://jmvidal.cse.sc.edu/lib/crockford08a.html
  5. taken, http://www.davidflanagan.com/javascript5/
  6. wikipedia:Javascript, http://www.wikipedia.org/wiki/Javascript
  7. by itself, http://developer.mozilla.org/en/docs/About_JavaScript
  8. SpiderMonkey, http://developer.mozilla.org/en/docs/SpiderMonkey
  9. Rhino, http://www.mozilla.org/rhino/
  10. Chrome, http://www.google.com/chrome
  11. firefox 3.1, http://www.mozilla.com/en-US/firefox/all-beta.html
  12. 0.1 + 0.2, javascript:alert(0.1 + 0.2)
  13. 'steve'.length, javascript:alert('steve'.length)
  14. 'steve'.charAt(1), javascript:alert('steve'.charAt(1))
  15. 'steve'.substring(1,4), javascript:alert('steve'.substring(1,4))
  16. 'steve'.indexOf('e'), javascript:alert('steve'.indexOf('e'))
  17. Number('1.0') + Number('2'), javascript:alert(Number('1.0') + Number('2'))
  18. if (1) {'yes'} else {'no'}, javascript:if (1) {'yes'} else {'no'}
  19. if (0) {'yes'} else {'no'}, javascript:if (0) {'yes'} else {'no'}
  20. if (1 == 0) {'yes'} else {'no'}, javascript:if (1 == 0) {'yes'} else {'no'}
  21. 'What he said is ' + (1 == 0), javascript:'What he said is ' + (1 == 0)
  22. square(5);, javascript:alert(square(5))
  23. doublef(plusone,5), javascript:alert(doublef(plusone,5));
  24. a;, javascript:alert(a);
  25. var now = new Date(), javascript:alert(new Date())
  26. m;, javascript:alert(m);
  27. xmas != solstice_plus_4, javascript:alert(xmas != solstice_plus_4)
  28. t;, javascript:alert(t)
  29. '1' == true, javascript: '1' == true
  30. var v = {x:1}; v == {x:1}, javascript:var v = {x:1}; v == {x:1}
  31. var v = {x:1}; v == v, javascript:var v = {x:1}; v == v
  32. '1' === true, javascript: '1' === true
  33. var v = {x:1}; v === {x:1}, javascript:var v = {x:1}; v === {x:1}
  34. var v = {x:1}; v === v, javascript:var v = {x:1}; v === v
  35. var p = {x:1,y:1}; 'y' in p, javascript:var p = {x:1,y:1}; 'y' in p
  36. var p = {x:1,y:1}; 'z' in p, javascript:var p = {x:1,y:1}; 'z' in p
  37. var d = new Date(); d instanceof Date, javascript:var d = new Date();d instanceof Date
  38. var d = new Date(); d instanceof Object, javascript:var d = new Date();d instanceof Object
  39. var d = new Date(); d instanceof Number, javascript:var d = new Date();d instanceof Number
  40. 1 + 2, javascript: 1 + 2
  41. '1' + '2', javascript: '1' + '2'
  42. '1' + 2, javascript: '1' + 2
  43. '11' < '2', javascript: '11' < '2'
  44. '11' < 2, javascript: '11' < 2
  45. 1 + 2 + ' blind mice', javascript: 1 + 2 + ' blind mice'
  46. 'blind mice=' + 1 + 3, javascript: 'blind mice=' + 1 + 3
  47. Run, javascript:var d = {x:1, y:2};for (var prop in d){alert(prop + ':' + d[prop]);}
  48. var d = new Date(); d.constructor==Date, javascript:var d = new Date(); d.constructor==Date;
  49. var o={x:1,y:2};alert(o.toString());, javascript:var o={x:1,y:2};alert(o.toString());
  50. var now = new Date();alert(now.valueOf());, javascript:var now = new Date();alert(now.valueOf());
  51. var a = new Array();, javascript:var a = new Array();alert(a.length);
  52. var a = new Array(10);, javascript:var a = new Array(10);alert(a.length);
  53. var a = [4,5];, javascript:var a = [4,5];alert(a.length);
  54. var a = [4,5];, javascript:var a = [4,5]; a[10] = 3; alert(a.length);
  55. var a =[1,2,3];, javascript:var a =[1,2,3];alert(a.join('=='));
  56. var a=[1,2,3];, javascript:var a=[1,2,3];alert(a.reverse());
  57. var a=['beta','alpha','delta'];, javascript:var a=['beta','alpha','delta'];alert(a.sort());
  58. var a=[1,2,3,4];, javascript:var a=[1,2,3,4];alert(a.sort(function(x,y){return y-x;}));
  59. var a=[1,2,3];, javascript:var a=[1,2,3];alert(a.concat(4,5));
  60. a.concat([4,5]);, javascript:var a=[1,2,3];alert(a.concat([4,5]));
  61. a.concat([4,5],[6,7]);, javascript:var a=[1,2,3];alert(a.concat([4,5],[6,7]));
  62. a.concat(4,5,[6,[7,8]]);, javascript:var a=[1,2,3];alert(a.concat(4,5,[6,[7,8]]));
  63. var a=[1,2,3,4,5];, javascript:var a=[1,2,3,4,5];alert(a.slice(0,3));
  64. a.slice(3);, javascript:var a=[1,2,3,4,5];alert(a.slice(3));
  65. a.slice(1,-1);, javascript:var a=[1,2,3,4,5];alert(a.slice(1,-1));
  66. a.slice(-3,-1);, javascript:var a=[1,2,3,4,5];alert(a.slice(-3,-1));
  67. var a=[1,2,3,4,5,6,7,8];, javascript:var a=[1,2,3,4,5,6,7,8];alert(a.splice(4));
  68. var a=[1,2,3,4,5,6,7,8];, javascript:var a=[1,2,3,4,5,6,7,8];alert(a.splice(1,2));
  69. var a=[1,2,3,4,5,6,7,8];, javascript:var a=[1,2,3,4,5,6,7,8];alert(a.splice(2,4));
  70. getArguments(1,2,3), javascript:alert(getArguments(1,2,3))
  71. getArguments('hi', 2), javascript:alert(getArguments('hi',2))
  72. getArguments(), javascript:alert(getArguments())
  73. getCaller(), javascript:alert(getCaller())
  74. i;, javascript:alert(i)
  75. j;, javascript:alert(j)
  76. k;, javascript:alert(k)
  77. calculator.compute();, javascript:calculator.compute()
  78. calculator.result, javascript:alert(calculator.result)
  79. function foo(x,y,z){};, javascript:function foo(x,y,z){};alert(foo.length)
  80. getuid(), javascript:alert(getuid())
  81. hypotenuse(2,2);, javascript:alert(hypotenuse(2,2))
  82. x;, javascript:alert(x);
  83. f();, javascript:f();
  84. x;, javascript:alert(x);
  85. g();, javascript:g();
  86. a[0]();, javascript:alert(a[0]());
  87. a[1]();, javascript:alert(a[1]());
  88. a[2]();, javascript:alert(a[2]());
  89. o.getName(), javascript:alert(o.getName())
  90. o.setName(123), javascript:alert(o.setName(123))
  91. o.getName(), javascript:alert(o.getName())
  92. o.setName('Joe'), javascript:o.setName('Joe')
  93. o.getName(), javascript:alert(o.getName())
  94. inspect(function (x) {return eval(x);}, 'Hello'), javascript:inspect(function (x) {return eval(x);}, 'Hello')
  95. factorial(5);, javascript:alert(factorial(5));
  96. wikipedia:Factory_pattern, http://www.wikipedia.org/wiki/Factory_pattern
  97. r1, javascript:alert(r1)
  98. r1.area(), javascript:alert(r1.area())
  99. employee.name;, javascript:alert(employee.name)
  100. human.name = 'Pink';, javascript:alert(human.name = 'Pink')
  101. employee.name;, javascript:alert(employee.name)
  102. employee.name = 'Blue';, javascript:alert(employee.name = 'Blue')
  103. human.name;, javascript:alert(human.name)
  104. '---' + ' hello there '.trim() + '---', javascript:alert('---' + ' hello there '.trim() + '---')
  105. template.supplant(data) , javascript:alert(template.supplant(data));
  106. wikipedia:Duck_typing, http://www.wikipedia.org/wiki/Duck_typing
  107. JSAN, http://www.openjsan.org
  108. wikipedia:Regular_expressions, http://www.wikipedia.org/wiki/Regular_expressions
  109. 'javascript'.search(/scr/i), javascript:alert('javascript'.search(/scr/i))
  110. 'javascript'.search(/joe/i), javascript:alert('javascript'.search(/joe/i))
  111. '1 plus 2 equals 3'.match(/\d+/g), javascript:alert('1 plus 2 equals 3'.match(/\d+/g))

This talk available at http://jmvidal.cse.sc.edu/talks/javascript/
Copyright © 2009 José M. Vidal . All rights reserved.

27 January 2009, 09:43AM