Web Programming Step by Step

Lecture 27
Object-Oriented JavaScript

Except where otherwise noted, the contents of this presentation are Copyright 2009 Marty Stepp and Jessica Miller.

Valid XHTML 1.1 Valid CSS!

Lecture Outline

Why use classes and objects?

object

Creating a new anonymous object

var name = {
	fieldName: value,
	...
	fieldName: value
};
var pt = {
	x: 4,
	y: 3
};
alert(pt.x + ", " + pt.y);

You've already done this...

new Ajax.Request("http://example.com/app.php",
	{
		method: "get",            // an object with a field named method (String)
		onSuccess: ajaxSuccess    // and a method named onSuccess
	}
);

$("my_element".fade(
	{
		duration: 2.0,            // an object with 3 fields named:
		from: 1.0,                // duration, from, and to (Number)
		to: 0.5
	}
);

Objects that have behavior (functions/methods)

var name = {
	...
	methodName: function(parameters) {
		statements;
	}
};
var pt = {
	x: 4,  y: 3,
	distanceFromOrigin: function() {
		return Math.sqrt(this.x * this.x + this.y * this.y);
	}
};

alert(pt.distanceFromOrigin());   // 5

A poor attempt at a "constructor"

What if we want to create an entire new class, not just one object?

Constructor functions

// Constructs and returns a new Point object.
function Point(xValue, yValue) {
	this.x = xValue;
	this.y = yValue;
	this.distanceFromOrigin = function() {
		return Math.sqrt(this.x * this.x + this.y * this.y);
	};
}
var p = new Point(4, -3);

Problems with our constructor

// Constructs and returns a new Point object.
function Point(xValue, yValue) {
	this.x = xValue;
	this.y = yValue;
	this.distanceFromOrigin = function() {
		return Math.sqrt(this.x * this.x + this.y * this.y);
	};
}

A paradigm shift: prototypes

prototypes

An object's prototype chain

prototype chain

Constructors and prototypes

// also causes Point.prototype to become defined
function Point(xValue, yValue) {
	...
}

Modifying a prototype

// adding a method to the prototype
className.prototype.methodName = function(parameters) {
	statements;
}
Point.prototype.distanceFromOrigin = function() {
	return Math.sqrt(this.x * this.x + this.y * this.y);
};

Point prototype methods

// Computes the distance between this point and the given point p.	
Point.prototype.distance = function(p) {
	var dx = this.x - p.x;
	var dy = this.y - p.y;
	return Math.sqrt(dx * dx + dy * dy);
};

// Returns a text representation of this object, such as "(3, -4)".	
Point.prototype.toString = function() {
	return "(" + this.x + ", " + this.y + ")";
};

Modifying built-in prototypes

// add a 'contains' method to all String objects
String.prototype.contains = function(text) {
	return this.indexOf(text) >= 0;
};

// add a 'lightUp' method to all HTML DOM element objects
HTMLElement.prototype.lightUp = function() {
	this.style.backgroundColor = "yellow";
	this.style.fontWeight = "bold";
};

Practice problem: Favorite Movies

movies page

Pseudo-inheritance with prototypes

function SuperClassName(parameters) {   // "superclass" constructor
	...
};
function SubClassName(parameters) {     // "subclass" constructor
	...
};
SubClassName.prototype = new SuperClassName(parameters);   // connect them

Pseudo-inheritance example

// Constructor for Point3D "class"
function Point3D(x, y, z) {
	this.x = x;
	this.y = y;
	this.z = z;
};

Point3D.prototype = new Point(0, 0);   // set as "subclass" of Point

// override distanceFromOrigin method
Point3D.prototype.distanceFromOrigin = function() {
	return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
};

Classes and prototypes

Creating a class

className = Class.create({
	// constructor
	initialize : function(parameters) {
		this.fieldName = value;
		...
	},

	methodName : function(parameters) {	
		statements;
	},
	...
});

Class.create example

Point = Class.create({
	// Constructs a new Point object at the given initial coordinates.
	initialize: function(initialX, initialY) {
		this.x = initialX;
		this.y = initialY;
	},

	// Computes the distance between this Point and the given Point p.	
	distance: function(p) {
		var dx = this.x - p.x;
		var dy = this.y - p.y;
		return Math.sqrt(dx * dx + dy * dy);
	},

	// Returns a text representation of this Point object.	
	toString: function() {
		return "(" + this.x + ", " + this.y + ")";
	}
});

Inheritance

className = Class.create(superclass, {
	...
});
// Points that use "Manhattan" (non-diagonal) distances.
ManhattanPoint = Class.create(Point, {
	// Computes the Manhattan distance between this Point and p.
	// Overrides the distance method from Point.
	distance: function(p) {
		var dx = Math.abs(this.x - p.x);
		var dy = Math.abs(this.y - p.y);
		return dx + dy;
	},
	
	// Computes this point's Manhattan Distance from the origin.
	distanceFromOrigin: function() {
		return this.x + this.y;
	}
});

Referring to superclass: $super

name: function($super, parameters) {
	statements;
}
ManhattanPoint3D = Class.create(ManhattanPoint, {
	initialize: function($super, initialX, initialY, initialZ) {
		$super(initialX, initialY);   // call Point constructor
		this.z = initialZ;
	},
	
	// Returns 3D "Manhattan Distance" from p.
	distance: function($super, p) {
		var dz = Math.abs(this.z - p.z);
		return $super(p) + dz;
	},
});

Practice problem: Fancy movies

movies page v2