Functions, Classes, and Methods in JavaScript

For any useful advice you want to share, on any subject under the sun.

Moderator: Thought Police

Locked
heavy-rotation
Thought Police
Thought Police
Posts: 1205
Joined: Thu Mar 14, 2002 12:11 pm
Location: Macclesfield
Contact:

Functions, Classes, and Methods in JavaScript

Post by heavy-rotation »

Functions are a fairly simple concept, in their simplest form they allow you to group code together that you can then call one or more times by name. An example:

Code: Select all

function greetUser ()
{
	document.write ('Hello user.');
}
Now whenever you use greetUser () in your script, 'Hello user' is printed to the page (without quotes). Now this is nice etc. but pretty much useless, so to make functions more flexible you can pass paramaters (known as arguments) to it. For example:

Code: Select all

function greetUser (name)
{
	document.write ('Hello ' + name + '.');
}
As you probably noticed, I added an argument called name. Whatever names you specify in the brackets after the function name become local variables inside the scope of that function when it is called. The function now writes whatever word you specify (although its intended to be a name in this case ;)) after 'Hello', so greetUser ('Gary') would print 'Hello Gary.' (again, without quotes).

This illustrates the fact the variable is local to the function:

Code: Select all

greetUser ('Gary');
alert (name);
This should now give an error - you can't 'alert' something that doesn't exist (alert just pops up a box with whatever argument you give it).

While this function may be of a little use, it still is quite locked down in functionality - when it's called, the result is immediately printed. You can't actually do anything with the result. Enter the 'return' keyword. Return allows you to process or create whatever object, string, number etc. then pass back out the result.

Code: Select all

function multiplyNumbers (n1, n2)
{
	return n1 * n2;
}
Another totally useless function I'm afraid, but its good for illustrative purposes. See how there are now two arguments, and, the result is returned. You would use a returning function such as this one, something like this:

Code: Select all

var twoNines = multiplyNumbers (2, 9);
document.write (twoNines);
Although, you don't have to use actually have to use an intermediary variable if you're just passing it straight to another function:

Code: Select all

document.write (multiplyNumbers (2, 9));
There is one last piece of handy information relating to functions that I can show you (before things get strange anyway). You don't actually have to name your function arguments, and you can access these through an array named arguments, funnily enough. A semi useful example function:

Code: Select all

function averageNumbers ()
{
	var totalNum = arguments.length;
	var totalVal = 0;

	for (var i = 0; i < arguments.length; i++)
	{
		totalVal += arguments[i];
	}

	return totalVal / totalNum;
}
Now you can pass this any number of arguments (numbers in this case), and it will return the mean average number.

Code: Select all

alert (averageNumbers (1, 3, 5)); // alerts 3
alert (averageNumbers (1, 5)); // also alerts 3
alert (averageNumbers (50, 6, 9, 8, 25, 26)); // alerts 20.6666666...8 ;)
Last edited by heavy-rotation on Wed Jun 04, 2003 3:32 pm, edited 1 time in total.
heavy-rotation
Thought Police
Thought Police
Posts: 1205
Joined: Thu Mar 14, 2002 12:11 pm
Location: Macclesfield
Contact:

Post by heavy-rotation »

Part 2: Things Get Weird.

Functions can be defined in a number of ways, the most common and useful two are:

Code: Select all

function func1 ()
{
... statements ...
}

func2 = function ()
{
... statements ...
}

You can also assign functions different names:

Code: Select all

theFunc = function ()
{

}

theSameFunc = theFunc
There theSameFunc when called would do the same as theFunc. There is an actual real use for this as I'm about to illustrate.

Functions in JavaScript can also act as classes (as you would find in a 'proper' OO language). A class is basically an object with functions attached, and some other interesting bits and bobs. An example object:

Code: Select all

Dog = new Object ();
Dog.furColour = "Dark Brown";
Dog.furLength = "Short";
An example object with function attached:

Code: Select all

Dog = new Object ();
Dog.furColour = "Black";
Dog.furLength = "Long";

Dog.speak = function ()
{
	alert ('Woof!');
}
So now Dog.speak () would alert 'Woof!'. Great. Now there is a small problem, if you want two dogs you have all that setting up to do:

Code: Select all

Dog1 = new Object ();
Dog1.furColour = "Black";
Dog1.furLength = "Long";
Dog1.speak = function ()
{
	alert ('Woof!');
}

Dog2 = new Object ();
Dog2.furColour = "Black";
Dog2.furLength = "Long";
Dog2.speak = function ()
{
	alert ('Woof!');
}
Not exactly ideal. Enter classes:

Code: Select all

function Dog (furColour, furLength)
{
	this.furColour = furColour
	this.furLength = furLength
}

myDog = new Dog ('Black', 'Long');
myOtherDog = new Dog ('Brown', 'Short');
So now you can create dogs with new Dog (). I have also given the class constructor (Dog function) arguments that are then assigned to the new instance of Dog that is created. You don't need to return anything with class constructors - using the new keyword fixes this for you (whatever you assign new Dog to becomes the created class instance). Notice I now use this to refer to the object. If you create variables in the function without appending this. they just behave like normal variables.

So what happened to Dog.speak() I hear you ask? Well there are a few ways of assigning functions to classes (functions attached to classes or objects are called methods):

Code: Select all

function Dog (furColour, furLength)
{
	this.furColour = furColour
	this.furLength = furLength
	this.speak = function ()
	{
		alert ('Woof!')
	}
}
This isn't especially good, as it keeps the constructor object in memory until the current instance of Dog is destroyed, as well as creating an object to assign to whatever you new Dog()'d.

Code: Select all

function dogWoof ()
{
	alert ('Woof!')
}

function Dog (furColour, furLength)
{
	this.furColour = furColour
	this.furLength = furLength
	this.speak = dogWoof
}
Not bad, I thought this was the only way to do it when I first started with this stuff. It takes a function and brings it in to the current class instance's scope (I'll explain that more in a minute).

Code: Select all

function Dog (furColour, furLength)
{
	this.furColour = furColour
	this.furLength = furLength
}

Dog.prototype.spe
ak = function ()
{
	alert ('Woof!')
}
There we go. The prototype property is rather special. You can't access it from within Dog (this.prototype is undefined), it has to be done outside of the function - this is good, as it means you don't have to add the methods you need every time you create a new Dog - they are added as soon as you create an instance, and, it means you can begin playing with inheritance.

Rewind a step though, and just a point on scope. If you run a method of dog, you can access any other method or properties of the current instance by appending this (as when you define properties). For example:

Code: Select all

Dog.prototype.examine = function ()
{
	alert ('Fur Colour:' + this.furColour);
	alert ('Fur Length:' + this.furLength);
	this.speak ();
}
heavy-rotation
Thought Police
Thought Police
Posts: 1205
Joined: Thu Mar 14, 2002 12:11 pm
Location: Macclesfield
Contact:

Post by heavy-rotation »

Part 3: Inheritance.

Unfortunately Javascript could be better in this department (See: Actionscript in flash).

Inheritance is the principle of being able to have a class take another classes methods or class-global properties. You can overwrite them with new ones still, but it is often handy to inherit.

An example:

Code: Select all

function Animal () { } // nothing needs to happen here as we're purely using it for inheritance

Animal.prototype.play = function ()
{
	alert ('...do fun things here...');
}

Animal.prototype.speak = function ()
{
	alert (this.message);
}

function Dog (furColour, furLength) 
{ 
	this.message = 'Woof!';
	this.furColour = furColour;
	this.furLength = furLength;
}

Dog.prototype = new Animal (); // Here's where the magic happens

// And adding other methods after still works fine
Dog.prototype.examine = function () 
{ 
   alert ('Fur Colour:' + this.furColour); 
   alert ('Fur Length:' + this.furLength); 
   this.speak (); 
}

myDog = new Dog ('Brown', 'Short')
myDog.play ()
myDog.examine ()
As you can see, the Dog class can now use the play method too. Its quite simple to have several classes inherit from another, say you wanted to add a Cat too:

Code: Select all

function Cat (sneakLevel, name)
{ 
	this.message = 'Meow';
	this.sneakLevel = sneakLevel
	this.name = name;
}

Cat.prototype = new Animal (); // Inheriting from Animal again

myCat = new Cat (100, 'fluffy');
As you can see, you don't have to store the same information etc, as long as this.message is used in this case (that variable holds the message to display when the class speak()s).

Unfortunately, this is where the problems start: You cannot inherit from multiple classes, you cannot inherit from a class which already inherits from something else, you cannot access the superclass. The superclass is the class that is inherited from (Animal in the example). In proper OO languages, you can do this (as can you in Actionscript - super() calls the constructor of the super class, so you can make all inheriting classes accept the same information, or initialize in some particular way, and super.method() calls whatever method of the superclass - this allows you to overwrite the methods, then call them anyway).

You can however do some very hacky and/or strange workarounds to get similar functionality to this, one of which would be the way I used the Proxy design pattern in the other thread.

I rambled a bit here, so may clean this up later. :)
shtum
Delta (Bokanovsky)
Delta (Bokanovsky)
Posts: 167
Joined: Tue Sep 03, 2002 5:36 pm

Post by shtum »

i just noticed that you do your braces like me

that is, instead of the "normal":
for (blah) {

}

you do:
for (blah)
{

}

thought i would share.
DaBeeeenster
Beta-Mandarin
Beta-Mandarin
Posts: 893
Joined: Thu Sep 12, 2002 10:45 am
Location: Bondi Beach, Sydney ;)
Contact:

Post by DaBeeeenster »

GAH! YOU FART IN THE GENERAL DIRECTION OF ISO STANDARDS! FASCISTS!
Image
"All our beliefs are being challenged now, and rightfully so. They're stupid." - Bill Hicks
My Travels Blog
heavy-rotation
Thought Police
Thought Police
Posts: 1205
Joined: Thu Mar 14, 2002 12:11 pm
Location: Macclesfield
Contact:

Post by heavy-rotation »

shtum wrote:i just noticed that you do your braces like me

that is, instead of the "normal":
for (blah) {

}

you do:
for (blah)
{

}

thought i would share.
Yup, personally I find it much easier to read that way... plus my code layout used to be all over the place, so I just took a style and stuck with it :)
Locked