JavaScript Functions Part 2


The statement below is a function declaration, which creates a function that has a name — in this case hellothere — that can be used to reference and invoke the function. Much of this material is from the book Head First JavaScript Programming.

function hellothere(num) {
	for (var i = 0; i < num; i++) {
		console.log("Hello there!");
	}
}

And we can invoke the function by using the function name and any needed arguments.

hellothere(4);

There is another way to use the function keyword.

var sprint = function(num) {
	for (var i = 0; i < num; i++) {
		console.log("Sprinting!");
	}
};

The function does not have a name and it is on the right hand side of an assignment to a variable. Now when we use the function keyword this way—that is, within a statement, like an assignment statement—we call this a function expression. What we have is a reference to a function.

At first glance, it might appear as if there isn’t a big difference between function declarations and function expressions. There is, and to understand that difference we need to start by looking at how your code is treated by the browser at runtime. When the browser parses your page — before it evaluates any code—it’s looking for function declarations. When the browser finds one, it creates a function and assigns the resulting reference to a variable with the same name as the function. So a variable is set up and it is a reference to the function. Now that all the function declarations have been taken care of, the browser goes back up to the top of your code and starts executing it, top to bottom.

We invoke functions created by declarations or created by expressions in exactly the same way. So what is the difference between declarations and expressions? Another difference has to do with function naming. When you use a declaration, the function name is used to create and set up as a variable that refers to the function. And, when you use a function expression, you typically don’t provide a name for the function, so either you end up assigning the function to a variable in code, or you use the function expression in other ways.

function quack(num) {
	for (var i = 0; i < num; i++) {
		console.log("Quack!");
	}
}
var fly = function(num) {
	for (var i = 0; i < num; i++) {
		console.log("Flying!");
	}
}
var superFly = fly;
superFly(2);
var superQuack = quack;
superQuack(3);

In the code above, fly is a reference to a function and so is superFly. And even though quack was created by a function declaration, the value in quack is a function reference too, so we can assign it to the variable superQuack and invoke it. You can think of functions as values too. Start thinking about functions as values, just like numbers, strings, booleans or objects.

First Class

Now you know that functions in JavaScript are values—values that can be assigned to variables. And you know that with values of other types, like numbers, booleans, strings and even objects, we can do all sorts of things with those values, like pass them to functions, return them from functions or even store them in objects or arrays.

First class: a value that can be treated like any other value in a programming language, including the ability to be assigned to a variable, passed as an argument, and returned from a function.

Passing Functions to Functions

Let’s start with just a simple data structure that represents passengers on an airline flight

var passengers = [ { name: "Jane Doloop", paid: true },
                   { name: "Dr. Evel", paid: true },
                   { name: "Sue Property", paid: false },
                   { name: "John Funcall", paid: true } ];

Here is our goal: write some code that looks at the passenger list and makes sure that certain conditions are met before the flight is allowed to take off. For instance, let’s make sure there are no passengers on a no-fly list. And let’s make sure everyone has paid for the flight. We might even want to create a list of everyone who is on the flight.

Now typically you’d write a function for each of these conditions: one to check the no-fly-list, one to check that every passenger has paid, and one to print out all the passengers. But if we wrote that code and stepped back to look at it, we’d find that all these functions look roughly the same, like this:

function checkPaid(passengers) {
	for (var i = 0; i < passengers.length; i++) {
		if (!passengers[i].paid) {
		return false;
		}
	}
return true;
}
function checkNoFly(passengers) {
	for (var i = 0; i < passengers.length; i++) {
		if (onNoFlyList(passengers[i].name)) {
		return false;
		}
	}
return true;
}
function printPassengers(passengers) {
	for (var i = 0; i < passengers.length; i++) {
		console.log(passengers[i].name);
		return false;
	}
return true;
}

That’s a lot of duplicated code: all these functions iterate through the passengers doing something with each passenger. And what if there are additional checks needed in the future? Say, checking to make sure laptops are powered down, checking to see if a passenger has an upgrade, checking to see if a passenger has a medical issue, and so on. That’s a lot of redundant code. Even worse, what if the data structure holding the passengers changes from a simple array of objects to something else? Then you might have to open every one of these functions and rewrite it. Not good.

A Better Way

We can solve this little problem with first class functions. Here’s how: we’re going to write one function that knows how to iterate through the passengers, and pass to that function a second function that knows how to do the check we need (that is, to see if a name is on a no-fly list, to check whether or not a passenger has paid, and so on).

function processPassengers(passengers, testFunction) {
	for (var i = 0; i < passengers.length; i++) {
		if (testFunction(passengers[i])) {
			return false;
		}
	}
	return true;
}
function checkNoFlyList(passenger) {
	return (passenger.name === "Dr. Evel");
}
function checkNotPaid(passenger) {
	return (!passenger.paid);
}
var allCanFly = processPassengers(passengers, checkNoFlyList);
if (!allCanFly) {
	console.log("The plane can't take off: we have a passenger on the no-fly-list.");
}
var allPaid = processPassengers(passengers, checkNotPaid);
if (!allPaid) {
	console.log("The plane can't take off: not everyone has paid.");
}
Series Navigation<< JavaScript Functions Part 1JavaScript Functions Part 3 >>

Leave a comment

Your email address will not be published. Required fields are marked *