Functions, expanded

Let's reiterate what was discussed in the JavaScript basics section. At their core there are only three or four parts to a function...

  • The "function" keyword
  • The function name
  • The structure of parenthesis followed by curly brackets
  • The function code / content written within the brackets

These components by themselves make the useful ability to able able to reuse code that can edit other parts of the document as we wish. But there's more to functions than just that. We can also use this code to make complex calculations that are self contained. For that we need to look at the "return" keyword.

Encapsulation

Before continuing it's important to convey the concept of "encapsulation".

Encapsulation describes how code is split into sections that typically only have access to one another in descending patterns.

Read the example to the right. Note the comments that show what will be output to the console when you try to run this code.

The error that is reported after the successful console logs is because that log function does not have the ability to see witihn the function. The variable "inside" only exists to other code within the function.

The variable "insiderer" within the if statement can be see within the function by JavaScript but it should be noted that this will not be the same for all programming languages.

Once an error is found JavaScript typically halts so the final "log" is not even run.

This concept is important because many students will try to access parts of one function (or "object" as you'll see) from another and receive an error for it. This may lead you to think that if you just place all of your variable outside of the function that it will be fine but doing that may also make your code harder to read. If a function needs temporary values to do what it is supposed to do and you, as the author, need to keep scrolling up to see those values it can generally become an annoyance.

You also have to consider possible conflicts. If you have math functions that find the area of shapes for instance; then the function that finds the area of a square and the function that finds the area of a circle might both try to assign values to an "area" variable causing conflicts.

If we keep the result of each function within the function itself then we can return it where we need to, when we need to, using the "return" keyword.



var outside = 1;

fun();

function fun(){	

	var inside = 2;
	
	if( 1 == 1 ){
		var insiderer = 3;
		
		console.log(outside);
		console.log(inside);
		console.log(insiderer);
		
	}	
	
	console.log(outside);
	console.log(inside);
	console.log(insiderer);

}

console.log(outside);
console.log(inside);
console.log(insiderer);
	
/*
Once run this code will output something
similar to the following:

1
2
3
1
2
3
1
Uncaught ReferenceError: 
	inside is not defined
*/

What it means to "return"

In the previous section we used a function to directly edit a known variable. But what if we either didn't want a function to edit only that one variable or simply didn't even know which variable the function needed to affect. In such a case we can actually use a function as an assigned value to change the variable in question.

Using a function as an assigned value, as if it were a data type all its own, we can not only change variables dynamically but we can save space by reusing the function itself. There are two functions below that do essentially the same thing. Notice how the second could conceivably be applied to any variable.



var va = 1;

fa();

function fa(){	
	va = 2;
}

var vb = 1;

vb = fb();

function fb(){	
	return 2;
}

// All variables are now set to "2".

In the second function we see our use of "return". This literally returns the value succeeding it to whatever code called the function in the first place.

So now not only can the second function be applied to any variable we want (since it does not reference "vb" specifically) but the returned value can be changed as well since a function can contain any instructions we want before that is done.

The one thing to keep in mind about the "return" keyword is that it represents the end of the function. Once it is used the function should cease to run.



var heads_or_tails = fb();

function fb(){

	var random_number = Math.random();

	if( random_number > 0.5 ){
		return true;
	} else {
		return false;
	}
	
	heads_or_tails = 234523;
	
}

In the code above we have the culmination of everything discussed so far.

  • The "random_number" variable exists only within the function because of encapsulation (in fact we could just use "Math.random()" within the "if" statement.
  • If the random number is above a threshold we use "return" to assign a value to our "heads or tails" variable.
  • The last line that seems to assign a definitive number to the variable will never run because it comes AFTER we have already used the "return" command. The only way a "return" command might not end the function is if it is inside an if statement that was found to be false.

Arguments & Parameters

Now even if you didn't notice a huge difference between a function assigning values internally and returning values you saw how reliant on having pre-existing values were for each approach. What if we are not always sure of what our starting values will be? What if we want to be able to use the same function with different sets of starting data?

For this we can use "Arguments" and "Parameters".

An Argument is a value "passed" to a function when the function is called, for the function to use, and which can be different between function calls.

Once within the function the context of the these values change.

A Parameter is the "Representation" of a function argument while within the context of the function.

So in the example code below the "arguments" are the values that are written between the parenthesis of the called functions in the first three lines.



var result_a = Add( 4, 5 );		// Returns "9"
var result_b = Sub( 8, 6 );		// Returns "2"
var result_c = Sub( 9, 3 );		// Returns "6"

function Add( a_, b_ ){	
	var sum = a_ + b_;	
	return sum;
}

function Sub( a_, b_ ){	
	return a_ - b_;
}

The above code shows a few things.

  • Both of the functions above take two arguments each. We can have as few or as many arguments as we like for a function (but we need the arguments "passed in" to match the number of arguments in the function).
  • The numbers within the first three lines are the "arguments". The "parameters" are the representations of those arguments "a_" and "b_". The function does not know what the arguments are going to be until the code is run.
  • The Labels for the arguments ( "a_" and "b_" ) exist only within the function. They are traded for the input arguments when the function is run so that in the case of the "Add" function "a_" becomes "4" and "b_" becomes "5".
  • These arguments allows us to reuse the functions as much as we want. Hence the "Sub" function can be used twice and with different numbers in each case.
  • We don't need to find the result of our calculation within a variable first as shown in the "Add" function. It is possible to do calculations in JavaScript within the "return" line as you see in the "Sub" function.
  • Note: The parameters "a_" and "b_" can be written however the author of the code wishes. For this author placing a simple underscore "_" at the end of each is a simple way of showing that it is parameter and not a reference to another variable somewhere in the code. You can use whatever indication your wish.

    Unknown arguments

    What if you don't know the exact number of arguments that you want to send to a function?

    Under construction...

    
    
    fun();
    
    function Add(){
    	
    	return arguments[0];
    }