Web Programming Step by Step, 2nd Edition

Lecture XX: Object-Oriented JavaScript

Reading: none

Except where otherwise noted, the contents of this document are Copyright 2012 Marty Stepp, Jessica Miller, and Victoria Kirst. All rights reserved. Any redistribution, reproduction, transmission, or storage of part or all of the contents in any form is prohibited without the author's expressed written permission.

Valid HTML5 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