Prototyping

Contact Us or call 1-877-932-8228
Prototyping

Prototyping

Objects in JavaScript

You have already seen objects in JavaScript. In simple terms, objects are associative arrays or hashes: arrays where the element index is not a number starting at 0, but rather a string. Object elements can be methods (functions) as well: a function that returns a value. Consider the following example:

Code Sample:

AdvancedObjects/Demos/objects.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Simple Objects in JavaScript</title>
</head>
<body>
	<h1>Simple Objects in JavaScript</h1>
	<script>
		var jdoe = {fname:'Jane', lname:'Doe', age:32, fullName:function() {return this.fname + ' ' + this.lname}}
		document.write('First name: ');
		document.write(jdoe.fname);
		document.write('<hr>');
		document.write('Full name: ');
		document.write(jdoe.fullName());
	</script>
</body>
</html>

Code Explanation

On line 10 we create an object jdoe, with properties fname, lname, and age. The object also has method fullName() which returns the full name of the person by concatenating the first and last names together with a space. We access (as on lines 12 and 15) the properties and methods of an object with the dot operator: jdoe.fname, jdoe.fullName(), etc.

Prototyping in JavaScript

Our previous example gets us some way toward writing OOP code in JavaScript, but we need more. While jdoe is a perfectly nice, useful object, it would be helpful if we could define a pattern for any person, not just for one particular person named "Jane Doe". That way, if we decide later to add a field ("address", say, or "telephone number") for our person object, we wouldn't have to do it for every object.

In JavaScript, we use prototyping for this purpose: we create an object, assigning to it the required fields (attributes and methods), and then instantiate (create) other objects from it using the new keyword. The prototype object serves as a pattern or template for the other objects, all of which have the same fields as defined in the prototype. Let's look at an example:

Code Sample:

AdvancedObjects/Demos/prototyping.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Prototyping</title>
	<script>
		var Person = function(fname, lname, age) {
			this.fname = fname;
			this.lname = lname;
			this.age = age;
			this.fullName = function() {
				return this.fname + ' ' + this.lname;
			}
		}
	</script>
</head>
<body>
	<h1>Prototyping</h1>
	<script>
		var jdoe = new Person('Jane', 'Doe', 32);
		document.write('First name: ');
		document.write(jdoe.fname);
		document.write('<hr>');
		document.write('Full name: ');
		document.write(jdoe.fullName());

		document.write('<hr>');
		document.write('<hr>');

		var afung = new Person('Adam', 'Fung', 11);
		document.write('First name: ');
		document.write(afung.fname);
		document.write('<hr>');
		document.write('Full name: ');
		document.write(afung.fullName());
	</script>
</body>
</html>

Code Explanation

On line 7 we create an object Person - this object, with attributes (first and last names, age) and method (fullName()) matching our earlier example - serves as the prototype for the objects (jdoe, afung) we create below. Note the we create each of the prototyped objects with the new keyword.

Every JavaScript object has a prototype from which it inherits its fields - its methods and properties; the top-most ancestor of any object is the generic JavaScript Object object. You may be familiar with some built-in JavaScript objects - like Date, String, or Math. These built-in objects (which offer useful properties and methods for dealing with date, text-string, or mathematical entities) inherit, like any object, from Object.

Even when we used JavaScript objects previously just as associative arrays - when we used something like this:

var person = {fname:'Jane', lname:'Doe', age:32}

our object in fact inherited from Object. But now we are explicitly exploiting this inhertance to use objects for prototyping, to create an object-oriented class from which to create other objects.

We can "tack on" new methods to our existing prototype by using the prototype keyword, even after having defined the prototype object. Consider the following example:

Code Sample:

AdvancedObjects/Demos/addingPrototypeMethods.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Prototyping: Adding Methods</title>
	<script>
		var Person = function(fname, lname, age) {
			this.fname = fname;
			this.lname = lname;
			this.age = age;
			this.fullName = function() {
				return this.fname + ' ' + this.lname;
			}
		}
	</script>
</head>
<body>
	<h1>Prototyping: Adding Methods</h1>
	<script>
		var jdoe = new Person('Jane', 'Doe', 32);
		
		Person.prototype.isOldEnoughToVote = function() {
			return this.age >= 18;
		}

		Person.prototype.changeAge = function(age) {
			//test if age is an integer:
			if (!(Number(age) === age && age % 1 === 0)) {
				return;
			}
			//test if age is >= 0
			if (age <= 0) {
				return;
			}
			this.age = age;
		}

		document.write('First name: ');
		document.write(jdoe.fname);
		document.write('<hr>');
		document.write('Full name: ');
		document.write(jdoe.fullName());
		document.write('<hr>');
		document.write('Old enough to vote? ');
		document.write(jdoe.isOldEnoughToVote() ? 'yes' : 'no');

		jdoe.changeAge(4);

		document.write('<hr>');
		document.write('Age: ');
		document.write(jdoe.age);
		document.write('<hr>');
		document.write('Old enough to vote? ');
		document.write(jdoe.isOldEnoughToVote() ? 'yes' : 'no');

		jdoe.changeAge('stringnotanumber');

		document.write('<hr>');
		document.write('Age: ');
		document.write(jdoe.age);
		document.write('<hr>');
		document.write('Old enough to vote? ');
		document.write(jdoe.isOldEnoughToVote() ? 'yes' : 'no');
	</script>
</body>
</html>

Code Explanation

We define our Person object prototype as before. On line 20, we create a new object (jdoe) of prototype Person. Next, we add two new methods to the prototype:

  1. Function isOldEnoughToVote, which tests whether the object's age would allow them to vote in the United States, returning true if the age is greater than or equal to 18.
  2. Function changeAge, which checks to make sure that the supplied parameter is an integer and is greater than or equal to zero. If either of these conditions is not true (if the age parameter is a string, say, or has a value like -2) then the function returns without modifying the prototype member age. If the conditions are satisfied - if we have a valid age - then this.age is set to age.

Note that, even though we instantiated object jdoe (on line 20) before adding these prototype methods (beginning on line 22), we can call these methods on jdoe later.

Next