CSE 190M Web Programming

Lecture 22: Object-Oriented JavaScript

Reading: none

Except where otherwise noted, the contents of this document are Copyright 2012 Marty Stepp, Jessica Miller, Victoria Kirst and Roy McElmurry IV. 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...

$.ajax("http://example.com/app.php", {
	'method': "post",            // an object with a field named method (String)
	'timeout': 2000   					// and a field name timeout
});

$("<div>", {
	'css': {											// a css field
		'color': red
	},
	'id': 'myid',								// an id field
	'click': myClickHandler			// and a method called click
});

Objects that have behavior

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);
};

Exercise: Point methods

Modify prototypal-point.js. You can test it using this page that links to the javascript.

  • Add distance and toString methods.
  • Add an add method that returns a new Point
  • Add an origin constant that is a dummy point with x and y coordinates

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";
};

Pseudo-inheritance with prototypes

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

Exercise: Point3D

Write a Javascript class Point3D that uses Point as its prototype. This class should do the following:

  • Add a z field
  • Override any methods that need to be updated
  • Have a normalize method

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 distance method
Point3D.prototype.distance = function(other) {
	return Math.sqrt(Math.pow(this.x - other.x, 2) +
					 				Math.pow(this.y - other.y, 2) +
					 				Math.pow(this.z - other.z, 2));
}

jQuery Plugins

There are some guidelines that you must follow as a jQuery plugin:

jQuery Plugin template

This template demonstrates some of the guidelines of a jQuery plugin

jQuery.fn.myplugin = function(options) {
	var defaults = {...};
	var params = jQuery.extend(defaults, options);
	this.each(function(idx, e) {
		// do stuff with jQuery(e) instead of $(e)
	});
	// If you don't need a return, then enable chaining
	return this;
};

Exercise: jQuery W3C Plugin

  • Write a jQuery plugin that appends validators to the selected elements.
    • The plugin should accept a linkhost parameter that specifies the domain of the links
    • The plugin should accept an imghost parameter that specifies the domain of the images

Classes and prototypes

The pseudoclassical form can provide comfort to programmers who are unfamiliar with JavaScript, but it also hides the true nature of the language…In classical languages, class inheritance is the only form of code reuse. JavaScript has more and better options.
-- Douglas Crockford

Scope in Java

public class Scope {
public static int x = 10; public static void main(String[] args) {
System.out.println(x); if (x > 0) {
int x = 20; System.out.println(x);
} int x = 30; System.out.println(x);
}
}

Scope in JavaScript

var x = 10; function main() {
alert(x); x = 20; if (x > 0) { var x = 30; alert(x); } var x = 40; var func = function(x) {
alert(x);
} f(50);
}

Lack of Block Scope

for (var i = 0; i < 10; i++) {
	alert(i);
}
alert(i);		// 11
if (i > 5) {
	var j = 3;
}
alert(j);		// 3

Let Statement: the future

var x = 5;
var y = 0;
var z;
let (x = x + 10, y = 12, z = 3) {
	console.log(x, y, z);		// 15, 12, 3
}
console.log(x, y, z);			// 5, 0, undefined

Closures

Closure Example

var x = 1;
function f() {
	var y = 2;
	var ret = function() {
		var z = 3;
		console.log(x, y, z);
	};
	y = 10;
	return ret;
}
var g = f();
g();								// 1, 10, 3

Functional Objects

Functional Base Class

var name = function(param, ..., my) {
	// Define private members as local variables
	var privateField = ...;
	var privateMethod = function() { ... };

	// Define protected members by adding them to "my"
	if (!my) my = {};
	my.protectedField = ...;

	// Define public members by adding them to an object literal
	var self = {
		"publicField": ...,
		"publicMethod": function() { ... }
	};
	// Return the public object literal, this is our object
	return self;
}

Functional Subclass

var name = function(params, ..., my) {
	// Define more private members as local variables
	var newPrivateField = ...;

	// Link to superclass, override or create any protected members
	if (!my) my = {};
	var self = point(params, ..., my);
	my.overrideMethod = function() { ... };
	my.newProtectedField = ...;

	// Add additional public members
	self.newPublicField = ...;
	self.newPublicMethod = function() { ... };

	// Return extended base class, this is our object
	return self;
}

Exercise: Functional Point and Point3D

Use this page to test our code.

  • Rewrite Point as a functional object with the following
    • private distance method
    • protected distanceFromOrigin and toString methods
    • protected origin field
    • public x and y fields
    • distanceFromOrigin and toString should be publically accessible
  • Rewrite Point3D as a functional object with appropriately overridden fields and methods