-
Notifications
You must be signed in to change notification settings - Fork 4
Functions
// this is a named function; it's similar to assigning the function to a variable named add, see below
function add(a, b)
{
return a + b;
}
console.log(add(1, 1)); // prints 2
// or, they can be assigned to a variable:
var subtract = function(a, b)
{
return a - b;
}
console.log(subtract(2, 1)); // prints 1
// because are first-class objects, they can be passed around like objects, we can even do:
var operation = subtract;
console.log(operation(2, 1)); // prints 1
// see what we did there?
operation = add;
console.log(operation(1, 1)); // prints 2
Functions are a group of statements executed one after another within their own subprogram - think of them like a program within a program. A function can have parameters, that is, when you define a function, you can specify a required list inputs. Importantly, they can also define a return value. In JavaScript, essentially everything is an object, and same goes for functions, and because of this they are deemed "first-class-objects", so they can be stored in variables, passed as arguments to other functions, created within functions, and returned from functions.
To declare or define a named function, we use the keyword, function
, followed by a name we give the function. Functions are often by convention named using a verb, because usually they encapsulate the steps required to do somehthing. In short, think of functions as a way to define actions or ask for the state of something, like saveImage();
, or, isComplete();
.
Here's a very simple function that specifies two parameters and returns the sum of those two parameters:
function add(a, b)
{
return a + b;
}
This is called a named function, because we're giving it the name add. If we name the function, we can execute it again later in the program by its name.
So once declared, we can then execute it by stating its name, followed by open and closed parentheses () and passing arguments to meet the required parameters. You might also say, instead of execute, invoke, call, or run a function - those terms are synonymous when we speak about executing a function. Here's what executing one looks like:
/*
* Here, when we define the add function, a and b are called parameters:
*/
function add(a, b)
{
return a + b;
}
/*
* Here, when we execute the add function, the values 5 and 5 are
* called arguments, which we are passing into the add function:
*/
var sum = add(5, 5);
console.log(sum); // prints 10;
One thing that often confuses people is the different in nomenclature between parameters and arguments. In the above example, at the point of defining the add function, we specify that the function takes two parameters, a and b. At the point of executing the function, we pass in two arguments, the values 5 and 5. See the comments we've added, above.
By encapsulating a series of statements together, we can reuse the functionality of the steps within the function elsewhere in a program without having to redefine those steps. This helps keep a program more organized and aids in maintainability. Imagine a more complex function:
function isPointInPolygon(point, p) {
var x = point[0], y = point[1];
var inside = false;
for (var i = 0, j = p.length - 1; i < p.length; j = i++) {
var xi = p[i][0], yi = p[i][1];
var xj = p[j][0], yj = p[j][1];
var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
};
If you later find a better way of expressing this functionality, or if you discovered a bug in your code, by encapsulating these series of statements together in a function, you need only change the code in one place to upgrade or fix its functionality. This form of reuse is described be the D.R.Y principle in design: Don't repeat yourself.
Functions can also be defined anonymously, that is, without a name:
setTimeout(function(){ console.log("Time up!"); }, 1000);
Here, we're executing the built-in setTimeout function, which runs a timer for a specified number of milliseconds, in this case for 1 second. The first parameter of the setTimeout requires us to pass a callback function to be executed once the timer completes, and the second parameter is the number of milliseconds for which the timer will run. In this example, we've defined the callback function inline, without a name, so it is termed an anonymous function.
This example will run a timer for one second, then execute the anonymous callback function, which in turn will call the console.log function, and print the message "Times up!". Because there's no other reference to the callback function, that is, it's not assigned to a variable, and it was not declared with a name, once the timer runs out and the callback function is executed, it is no longer in memeory. This is a powerful pattern you'll see a lot in more advanced JavaScript applications.
Scope implies what is accessible where. Functions encapsulate their own scope, and functions within functions do the same, but we call those closures. To understand scope, imagine a room within a room, and people in the inner room can see into the outer room, but the people in the outer room cannot see the people inside the inner room. Functions form a closure around themselves to have their own little environment, and variables and values within that closure or scope cannot be seen or accessed outside that function unless the function returns the values:
var x = 1;
function doSomething(){
console.log('Starting doSomething...');
console.log(x); // prints 1
x += 1;
console.log(x); // prints 2
var y = 2;
console.log(y); // prints 2
console.log('Exiting doSomething...');
}
console.log(x); // prints 1
doSomething(); // see notes inside doSomething()...
console.log(x); // prints 2
console.log(y); // throws a ReferenceError: y is not defined
In this example, x is visible inside the function doSomething when it is exeecuted, but why, which is declared and initialized inside the function doSomthing, is not visible outside of the function doSomething.
© John Fraboni 2014