OOP in JS, Part 1 : Public/Private Variables and Methods

This page shows how to create private variables and methods in "classes" in Javascript through the rather simple example of a person. (This is really a very rough approximation of the classical OOP pattern, and not necessarily a "best-practice" for JavaScript programming.) Part 2 covers inheritance.

Summary

Example

In this example, a person's name and race are set at birth and may never be changed. When created, a person starts out at year 1 and a hidden maximum age is determined for that person. The person has a weight which is modified by eating (tripling their weight) or exercising (halfing it). Every time the person eats or exercises, they grow a year older. The person object has a publicly accessible 'clothing' property which anyone can modify, as well as a dirtFactor which can be modified manually (throwing dirt on or scrubbing it off), but which increases every time the person eats or exercises, and is reduced by the use of the shower() method.

<- click to run the example code below (the code block being run appears after the Person constructor).

The Example Code

function Person(n,race){
	this.constructor.population++;

	// ************************************************************************
	// PRIVATE VARIABLES AND FUNCTIONS
	// ONLY PRIVELEGED METHODS MAY VIEW/EDIT/INVOKE
	// ***********************************************************************
	var alive=true, age=1;
	var maxAge=70+Math.round(Math.random()*15)+Math.round(Math.random()*15);
	function makeOlder(){ return alive = (++age <= maxAge) }

	var myName=n?n:"John Doe";
	var weight=1;


	// ************************************************************************
	// PRIVILEGED METHODS
	// MAY BE INVOKED PUBLICLY AND MAY ACCESS PRIVATE ITEMS
	// MAY NOT BE CHANGED; MAY BE REPLACED WITH PUBLIC FLAVORS
	// ************************************************************************
	this.toString=this.getName=function(){ return myName }

	this.eat=function(){
		if (makeOlder()){
			this.dirtFactor++;
			return weight*=3;
		} else alert(myName+" can't eat, he's dead!");
	}
	this.exercise=function(){
		if (makeOlder()){
			this.dirtFactor++;
			return weight/=2;
		} else alert(myName+" can't exercise, he's dead!");
	}
	this.weigh=function(){ return weight }
	this.getRace=function(){ return race }
	this.getAge=function(){ return age }
	this.muchTimePasses=function(){ age+=50; this.dirtFactor=10; }


	// ************************************************************************
	// PUBLIC PROPERTIES -- ANYONE MAY READ/WRITE
	// ************************************************************************
	this.clothing="nothing/naked";
	this.dirtFactor=0;
}


// ************************************************************************
// PUBLIC METHODS -- ANYONE MAY READ/WRITE
// ************************************************************************
Person.prototype.beCool = function(){ this.clothing="khakis and black shirt" }
Person.prototype.shower = function(){ this.dirtFactor=2 }
Person.prototype.showLegs = function(){ alert(this+" has "+this.legs+" legs") }
Person.prototype.amputate = function(){ this.legs-- }


// ************************************************************************
// PROTOTYOPE PROERTIES -- ANYONE MAY READ/WRITE (but may be overridden)
// ************************************************************************
Person.prototype.legs=2;


// ************************************************************************
// STATIC PROPERTIES -- ANYONE MAY READ/WRITE
// ************************************************************************
Person.population = 0;



// Here is the code that uses the Person class
function RunGavinsLife(){
	var gk=new Person("Gavin","caucasian");       //New instance of the Person object created.
	var lk=new Person("Lisa","caucasian");        //New instance of the Person object created.
	alert("There are now "+Person.population+" people");

	gk.showLegs(); lk.showLegs();                 //Both share the common 'Person.prototype.legs' variable when looking at 'this.legs'

	gk.race = "hispanic";                         //Sets a public variable, but does not overwrite private 'race' variable.
	alert(gk+"'s real race is "+gk.getRace());    //Returns 'caucasian' from private 'race' variable set at create time.
	gk.eat(); gk.eat(); gk.eat();                 //weight is 3...then 9...then 27
	alert(gk+" weighs "+gk.weigh()+" pounds and has a dirt factor of "+gk.dirtFactor);

	gk.exercise();                                //weight is now 13.5
	gk.beCool();                                  //clothing has been update to current fashionable levels
	gk.clothing="Pimp Outfit";                    //clothing is a public variable that can be updated to any funky value
	gk.shower();
	alert("Existing shower technology has gotten "+gk+" to a dirt factor of "+gk.dirtFactor);

	gk.muchTimePasses();                          //50 Years Pass
	Person.prototype.shower=function(){           //Shower technology improves for everyone
		this.dirtFactor=0;
	}
	gk.beCool=function(){                         //Gavin alone gets new fashion ideas
		this.clothing="tinfoil";
	};

	gk.beCool(); gk.shower();
	alert("Fashionable "+gk+" at "
		+gk.getAge()+" years old is now wearing "
		+gk.clothing+" with dirt factor "
		+gk.dirtFactor);

	gk.amputate();                                //Uses the prototype property and makes a public property
	gk.showLegs(); lk.showLegs();                 //Lisa still has the prototype property

	gk.muchTimePasses();                          //50 Years Pass...Gavin is now over 100 years old.
	gk.eat();                                     //Complains about extreme age, death, and inability to eat.
}

Notes

This page copyright ©2003 by Gavin Kistner. Comments, corrections, and criticisms are welcome.