Javascript Objects v Functions (level: beginner/intermediate)

Pros and cons of Object with methods and Functions

A great deal of javascript is still written in a functions based way, it needn't be, javascript Objects are good for the little jobs too and aren't any harder to write.

Pros of 00 scripting

  • Code is reusable/portable
  • Promotes grouping of functionality into objects
  • Easier to maintain and upgrade
  • Redundant code is easy to identify and remove
  • Promotes documentation
  • Easier to implement error handling

Pros of function based scripting

  • Quicker initial development
  • Looks slightly simpler to read
  • Can run quicker (matter of debate)

Objectives

In this example we are going to look at a simple bit of javascript, done in two ways, Function based and Object based to compare the two methods

  • Technical overview of the differences
  • A feel for the different way of thinking when using objects rather than functions.

If you are a javascript beginner, 00 scripting might seem a little hard-core and not something that you need to worry about, however, although javascript objects may look a little more complex in actual fact they are probably easier to get to grips with than you imagine and much easier to add new functionality to. This is beacuse an object can contains as many little methods as you like so it's easyer to manage and will be better and quicker to work with in the long run.
You don't need to know exactly what all the examples do, you can just skip over the code, you'll still get a feel for the two different approches.

Probably the best way to illustrate the differences between 00 scripting and functions based scripting is to have a quick look at a simple example.

Scenario:
  • User enters a web page, if they came from a sister site which knows their name, their name is in the query string
  • On our landing page we'll write: "Welcome <user name>" if we know their name and "Welcome Guest user" if we don't

Let's build a page that for fills the requirements with a function.

example 1, step 1:  

Firstly we'll need a function to get the data from the query string

<script>
function getQueryStringName(defaultValue){
	var query = window.location.search.substring(1);
	var pairs = query.split("&");	
	var KEY   = "name";
	var value ;
	for (var i=0;i<pairs.length;i++)
	{
		var pos = pairs[i].indexOf('=');
		if (pos >= 0 && pos < pairs[i].length-1) // the = is not the first or last char
		{
			var key = pairs[i].substring(0,pos);
			var temp = pairs[i].substring(pos+1);
			if (key == KEY){ // is this the key we want?
				temp = unescape(temp);
				value = temp.replace(/\+/g," ");
				break;
			}
		}
	}
	return ( value || defaultValue );
}
</script>

If we have a quick look at the function, it's expecting one parameter, a string called 'KEY' (in our example it'll be 'name'). It get's the querystring and splits it into key=value pairs (these are separated by an &). Then it loops though all the pairs to see if there is one where the key matches the KEY variable passed in. If there is it returns the value associated with the key. If not it returns an empty string by default.

example 1, step 2: view example

Write the data to the screen

Welcome <strong><script type="text/javascript">
document.write( getQueryStringName('Gest user') );
</script></strong>

Now we are looking for a value for 'name' in the querystring, if we get an empty string we'll substitute "Guest user" instead and write the result to the screen, using the built in javascript method document.write().

example 2, step 1:

Let's do the same as above, but with an object instead of a function

<script type="text/javascript">

/** @id QuerySting */
function QuerySting()
{
	// properties
	this.query 		= window.location.search.substring(1);
	this.pairs 		= this.query.split("&");	
	this.keys 		= new Array();
	this.values 	= new Array();
	
	// methods
	this.get 		= Get;		// expects a key argument, returns a value
	this.init		= Init;		// sets up the key value arrays 
	
	// we know that we'll need this on this page so run init();
	this.init();	
	
	// load the key value pairs
	/** @id QuerySting.Init */
	function Init()
	{
		for (var i=0;i<this.pairs.length;i++)
		{
			var pos = this.pairs[i].indexOf('=');
			if (pos > 0  && pos < this.pairs[i].length-1)
			{
				var key = this.pairs[i].substring(0,pos);
				this.keys[this.keys.length] = key;

				var value = this.pairs[i].substring(pos+1);
				value = unescape(value);
				this.values[this.values.length] = value.replace(/\+/g," ");
			}
		}
	}
	
	/** @id QuerySting.Get */
	function Get(KEY)
	{
		var value = new String;
		for (var i=0;i<this.pairs.length;i++)
		{
			if (this.keys[i]==KEY)
			{
				value = this.values[i];
				break;
			}
		}
		return value;
	}
	

}

var querySting = new QuerySting;

</script>

So, the object looks more complex than the function in [example 1 step 1] did. The Object contains two methods that do the same job as the function, i.e. create the key/value arrays and return the value that corresponds to the KEY variable.
The Init() function takes the variable pairs array and loops though to build the key/value arrays. And the Get function returns the value corresponding to the KEY variable passed in.
The function in [example 1 step 1] does both jobs in one go, functions tend to amalgamate functionality into one function where as objects tend to contain many small functions that do specific tasks.

example 2, step 2: view example

Now to write the data to screen we'll do to things, firstly we'll add a WriteValue() method to our object and then we'll call it from the page.

<script type="text/javascript">

/** @id QuerySting */
function QuerySting()
{
	// properties
	...
	
	// methods
	...
	this.writeValue	= WriteValue; 	// write a value to screen
	
	...
		
	/** @id QuerySting.WriteValue */
	function WriteValue(KEY,defaultValue)
	{
		document.write( this.get(KEY) || defaultValue );
	}
}
</script>

You can see we've added a very small method (in red) to our queryString object above, now we can just call this from the page

Welcome <strong><script type="text/javascript">
queryString.writeValue('name','Guest user');
</script></strong>

Now we are passing in the key and default text and letting the function do the work, this is a nicer way of achieving the same thing as the function.


Section 2

Ok, lets assume that the requirements change, now we are going to try to encourage people to sign up by pre populating a form with the querystring data, instead of writing it to screen.

example 3, step 1: view example

We are going to amend our welcome page by adding a form and if the users details are in the querystring we'll popuplate the form.
Ok, so let's say we've added a form to the HTML and then we'll amend our function so that it loads the form values, if they exist in the query string.

<script type="text/javascript">
function getQueryString(){
	var query = window.location.search.substring(1);
	var pairs = query.split("&");	
	var keyValues = new Array;
	for (var i = 0 ; i < pairs.length ; i++)
	{
		var pos = pairs[i].indexOf('=');
		if (pos >= 0 && pos < pairs[i].length-1)
		{
			var key = pairs[i].substring(0,pos);
			var value = pairs[i].substring(pos+1);
			keyValues[key] = value; 
		}
	}
	document.getElementById('inputFirstName').value = ( keyValues['firstName'] || "" );
	document.getElementById('inputSurname').value = ( keyValues['surname'] || "" );
	document.getElementById('inputEmail').value = ( keyValues['email'] || "" );
}
</script>

We have changed how the function works a little I've removed a couple of lines and added a couple, additions in red. Now the function loads the form values instead of writing to the screen.

example 4, step 1: view example

Let's do the same for our object, but instead of changing the what it does, we are going to add a new method to it in order to meet the new requirement.
In an object oriented way of thinking you'll probably not just make a method to load the values for the current two form elements, your more likely be thinking in terms of the form object so the method we'll add to our QueryString object is more likely to be something like this.

<script type="text/javascript">
function QuerySting()
{
	// properties
	...
	
	// methods
	...
	this.loadForm = LoadForm;
	
	// ...
	function LoadForm(formName)
	{
		var form = document.forms[formName];
		for (var i = 0; i < form.elements.length; ++i) 
		{
			if ( form.elements[i].type == "text"  && this.get(form.elements[i].name )){
				form.elements[i].value = this.get(form.elements[i].name);
			}
		}
	}	
}
</script>

Ok, so we've added a method that expects a string form name, which is the name of the form you want to load, and then we are looping though all the form elements, if the form element is type = 'text' (a normal form element, not a checkbox or select dropdown etc...) and there is a value which matches the form element name (e.g. a form element name="email" will match because we are passing in an 'email' querystring param with that key).
We are still using the queryStirng.get that we originally made, we aren't using the querySting.writeValue any more. But we haven't removed it.

Conclusion

Ok, so we have two ways of doing the same thing, the fuction way and the object way. The object was more complex to start with, but when the requirements changed we just extended our object by adding a small method. We had to rewrite the function to make it do what we wanted it to do.

The function is tied to the page as it's got element ids hard coded in it, whist the object doesn't, it's reusable, we can just pick it up and put in another page without having to modify it at all. We may at a later date, but we can carry on adding extra methods without loosing the existing functionally.

Let's imagine it's 5pm on Friday and your project manager comes in and tells you that everything is fine, but they want the "Welcome .." message put back in and they have added postcode and telephone fields to the form.

Function: If you where using the function you would have to amend the HTML to add the form elements, you would probably have to duplicate the function because it can't do both actions, write to the screen and load the form element values, and you would have to update the function to load the two new form elements.

Object: If your using the object all you have to do is edit the HTML, you need to add the new form elements, the javascript will load the values automatically, because it's looping though all the form elements, and we still have the .writeValue() method so we can just re-implement the welcome message again. We don't need to touch the javascript at all. So we can still be down the pub by 5.30! Full example

- ends -