Functions - Object-Oriented JavaScript Second Edition (2013)

Object-Oriented JavaScript Second Edition (2013)

Chapter 3. Functions

Mastering functions is an important skill when you learn any programming language, and even more so when it comes to JavaScript. This is because JavaScript has many uses for functions, and much of the language's flexibility and expressiveness comes from them. Where most programming languages have a special syntax for some object-oriented features, JavaScript just uses functions. This chapter will cover:

· How to define and use a function

· Passing arguments to a function

· Predefined functions that are available to you "for free"

· The scope of variables in JavaScript

· The concept that functions are just data, albeit a special type of data

Understanding these topics will provide a solid base that will allow you to dive into the second part of the chapter, which shows some interesting applications of functions:

· Using anonymous functions

· Callbacks

· Immediate (self-invoking) functions

· Inner functions (functions defined inside other functions)

· Functions that return functions

· Functions that redefine themselves

· Closures

What is a function?

Functions allow you to group together some code, give this code a name, and reuse it later, addressing it by the name you gave it. Let's see an example:

function sum(a, b) {

var c = a + b;

return c;

}

The parts that make up a function are shown as follows:

· The function statement.

· The name of the function, in this case sum.

· The function parameters, in this case a and b. A function can take any number of parameters, separated by commas.

· A code block, also called the body of the function.

· The return statement. A function always returns a value. If it doesn't return a value explicitly, it implicitly returns the value undefined.

Note that a function can only return a single value. If you need to return more values, you can simply return an array that contains all of the values you need as elements of this array.

The preceding syntax is called a function declaration. It's just one of the ways to create a function in JavaScript, and more ways are coming up.

Calling a function

In order to make use of a function, you need to call it. You call a function simply by using its name optionally followed by any number of values in parentheses. "To invoke" a function is another way of saying "to call".

Let's call the function sum(), passing two arguments and assigning the value that the function returns to the variable result:

> var result = sum(1, 2);

> result;

3

Parameters

When defining a function, you can specify what parameters the function expects to receive when it's called. A function may not require any parameters, but if it does and you forget to pass them, JavaScript will assign the value undefined to the ones you skipped. In the next example, the function call returns NaN because it tries to sum 1 and undefined:

> sum(1);

NaN

Technically speaking, there is a difference between parameters and arguments, although the two are often used interchangeably. Parameters are defined together with the function, while arguments are passed to the function when it's called. Consider this:

> function sum(a, b) {

return a + b;

}

> sum(1, 2);

Here, a and b are parameters, while 1 and 2 are arguments.

JavaScript is not picky at all when it comes to accepting arguments. If you pass more than the function expects, the extra ones will be silently ignored:

> sum(1, 2, 3, 4, 5);

3

What's more, you can create functions that are flexible about the number of parameters they accept. This is possible thanks to the special value arguments that is created automatically inside each function. Here's a function that simply returns whatever arguments are passed to it:

> function args() {

return arguments;

}

> args();

[]

> args( 1, 2, 3, 4, true, 'ninja');

[1, 2, 3, 4, true, "ninja"]

By using arguments, you can improve the sum() function to accept any number of arguments and add them all up:

function sumOnSteroids() {

var i,

res = 0,

number_of_params = arguments.length;

for (i = 0; i < number_of_params; i++) {

res += arguments[i];

}

return res;

}

If you test this function by calling it with a different number of arguments (or even none at all), you can verify that it works as expected:

> sumOnSteroids(1, 1, 1);

3

> sumOnSteroids(1, 2, 3, 4);

10

> sumOnSteroids(1, 2, 3, 4, 4, 3, 2, 1);

20

> sumOnSteroids(5);

5

> sumOnSteroids();

0

The expression arguments.length returns the number of arguments passed when the function was called. Don't worry if the syntax is unfamiliar, we'll examine it in detail in the next chapter. You'll also see that arguments is not an array (although it sure looks like one), but an array-like object.

Predefined functions

There are a number of functions that are built into the JavaScript engine and are available for you to use. Let's take a look at them. While doing so, you'll have a chance to experiment with functions, their arguments and return values, and become comfortable working with functions. Following is a list of the built-in functions:

· parseInt()

· parseFloat()

· isNaN()

· isFinite()

· encodeURI()

· decodeURI()

· encodeURIComponent()

· decodeURIComponent()

· eval()

Tip

The black box function

Often, when you invoke functions, your program doesn't need to know how these functions work internally. You can think of a function as a black box: you give it some values (as input arguments) and then you take the output result it returns. This is true for any function—one that's built into the JavaScript engine, one that you create, or one that a co-worker or someone else created.

parseInt()

parseInt() takes any type of input (most often a string) and tries to make an integer out of it. If it fails, it returns NaN:

> parseInt('123');

123

> parseInt('abc123');

NaN

> parseInt('1abc23');

1

> parseInt('123abc');

123

The function accepts an optional second parameter, which is the radix, telling the function what type of number to expect—decimal, hexadecimal, binary, and so on. For example, trying to extract a decimal number out of the string FF makes no sense, so the result isNaN, but if you try FF as a hexadecimal, then you get 255:

> parseInt('FF', 10);

NaN

> parseInt('FF', 16);

255

Another example would be parsing a string with a base 10 (decimal) and base 8 (octal):

> parseInt('0377', 10);

377

> parseInt('0377', 8);

255

If you omit the second argument when calling parseInt(), the function will assume 10 (a decimal), with these exceptions:

· If you pass a string beginning with 0x, then the radix is assumed to be 16 (a hexadecimal number is assumed).

· If the string you pass starts with 0, the function assumes radix 8 (an octal number is assumed). Consider the following examples:

· > parseInt('377');

· 377

· > parseInt('0377');

· 255

· > parseInt('0x377');

· 887

The safest thing to do is to always specify the radix. If you omit the radix, your code will probably still work in 99 percent of cases (because most often you parse decimals), but every once in a while it might cause you a bit of hair loss while debugging some edge cases. For example, imagine you have a form field that accepts calendar days or months and the user types 06 or 08.

Note

ECMAScript 5 removes the octal literal values and avoids the confusion with parseInt() and unspecified radix.

parseFloat()

parseFloat() is similar to parseInt(), but it also looks for decimals when trying to figure out a number from your input. This function takes only one parameter:

> parseFloat('123');

123

> parseFloat('1.23');

1.23

> parseFloat('1.23abc.00');

1.23

> parseFloat('a.bc1.23');

NaN

As with parseInt(), parseFloat() gives up at the first occurrence of an unexpected character, even though the rest of the string might have usable numbers in it:

> parseFloat('a123.34');

NaN

> parseFloat('12a3.34');

12

parseFloat() understands exponents in the input (unlike parseInt()):

> parseFloat('123e-2');

1.23

> parseFloat('1e10');

10000000000

> parseInt('1e10');

1

isNaN()

Using isNaN(), you can check if an input value is a valid number that can safely be used in arithmetic operations. This function is also a convenient way to check whether parseInt() or parseFloat() (or any arithmetic operation) succeeded:

> isNaN(NaN);

true

> isNaN(123);

false

> isNaN(1.23);

false

> isNaN(parseInt('abc123'));

true

The function will also try to convert the input to a number:

> isNaN('1.23');

false

> isNaN('a1.23');

true

The isNaN() function is useful because the special value NaN is not equal to anything including itself. In other words, NaN === NaN is false. So, NaN cannot be used to check if a value is a valid number.

isFinite()

isFinite() checks whether the input is a number that is neither Infinity nor NaN:

> isFinite(Infinity);

false

> isFinite(-Infinity);

false

> isFinite(12);

true

> isFinite(1e308);

true

> isFinite(1e309);

false

If you are wondering about the results returned by the last two calls, remember from the previous chapter that the biggest number in JavaScript is 1.7976931348623157e+308, so 1e309 is effectively infinity.

Encode/decode URIs

In a Uniform Resource Locator (URL) or a Uniform Resource Identifier (URI), some characters have special meanings. If you want to "escape" those characters, you can use the functions encodeURI() or encodeURIComponent(). The first one will return a usable URL, while the second one assumes you're only passing a part of the URL, such as a query string for example, and will encode all applicable characters:

> var url = 'http://www.packtpub.com/script.php?q=this and that';

> encodeURI(url);

"http://www.packtpub.com/scr%20ipt.php?q=this%20and%20that"

> encodeURIComponent(url);

"http%3A%2F%2Fwww.packtpub.com%2Fscr%20ipt.php%3Fq%3Dthis%20and%20that"

The opposites of encodeURI() and encodeURIComponent() are decodeURI() and decodeURIComponent() respectively.

Sometimes, in legacy code, you might see the functions escape() and unescape() used to encode and decode URLs, but these functions have been deprecated; they encode differently and should not be used.

eval()

eval() takes a string input and executes it as a JavaScript code:

> eval('var ii = 2;');

> ii;

2

So, eval('var ii = 2;') is the same as var ii = 2;.

eval() can be useful sometimes, but should be avoided if there are other options. Most of the time there are alternatives, and in most cases the alternatives are more elegant and easier to write and maintain. "Eval is evil" is a mantra you can often hear from seasoned JavaScript programmers. The drawbacks of using eval() are:

· Security – JavaScript is powerful, which also means it can cause damage. If you don't trust the source of the input you pass to eval(), just don't use it.

· Performance – It's slower to evaluate "live" code than to have the code directly in the script.

A bonus – the alert() function

Let's take a look at another common function—alert(). It's not part of the core JavaScript (it's nowhere to be found in the ECMA specification), but it's provided by the host environment—the browser. It shows a string of text in a message box. It can also be used as a primitive debugging tool, although the debuggers in modern browsers are much better suited for this purpose.

Here's a screenshot showing the result of executing the code alert("hello!"):

A bonus – the alert() function

Before using this function, bear in mind that it blocks the browser thread, meaning that no other code will be executed until the user closes the alert. If you have a busy Ajax-type application, it's generally not a good idea to use alert().

Scope of variables

It's important to note, especially if you have come to JavaScript from another language, that variables in JavaScript are not defined in a block scope, but in a function scope. This means that if a variable is defined inside a function, it's not visible outside of the function. However, if it's defined inside an if or a for code block, it's visible outside the block. The term "global variables" describes variables you define outside of any function (in the global program code), as opposed to "local variables", which are defined inside a function. The code inside a function has access to all global variables as well as to its own local ones.

In the next example:

· The f()function has access to the global variable

· Outside the f()function, the local variable doesn't exist

· var global = 1;

· function f() {

· var local = 2;

· global++;

· return global;

}

Let's test this:

> f();

2

> f();

3

> local;

ReferenceError: local is not defined

It's also important to note that if you don't use var to declare a variable, this variable is automatically assigned a global scope. Let's see an example:

Scope of variables

What happened? The function f()contains the variable local. Before calling the function, the variable doesn't exist. When you call the function for the first time, the variable local is created with a global scope. Then, if you access local outside the function, it will be available.

Tip

Best practice tips

· Minimize the number of global variables in order to avoid naming collisions. Imagine two people working on two different functions in the same script, and they both decide to use the same name for their global variable. This could easily lead to unexpected results and hard-to-find bugs.

· Always declare your variables with the var statement.

· Consider a "single var" pattern. Define all variables needed in your function at the very top of the function so you have a single place to look for variables and hopefully prevent accidental globals.

Variable hoisting

Here's an interesting example that shows an important aspect of local versus global scoping:

var a = 123;

function f() {

alert(a);

var a = 1;

alert(a);

}

f();

You might expect that the first alert() will display 123 (the value of the global variable a) and the second will display 1 (the local variable a). But, this is not the case. The first alert will show undefined. This is because inside the function the local scope is more important than the global scope. So, a local variable overwrites any global variable with the same name. At the time of the first alert(), the variable a was not yet defined (hence the value undefined), but it still existed in the local space due to the special behavior called hoisting.

When your JavaScript program execution enters a new function, all the variables declared anywhere in the function are moved (or elevated, or hoisted) to the top of the function. This is an important concept to keep in mind. Further, only the declaration is hoisted, meaning only the presence of the variable is moved to the top. Any assignments stay where they are. In the preceding example, the declaration of the local variable a was hoisted to the top. Only the declaration was hoisted, but not the assignment to 1. It's as if the function was written like this:

var a = 123;

function f() {

var a; // same as: var a = undefined;

alert(a); // undefined

a = 1;

alert(a); // 1

}

You can also adopt the single var pattern mentioned previously in the best practice section. In this case, you'll be doing a sort of manual variable hoisting to prevent confusion with the JavaScript hoisting behavior.

Functions are data

Functions in JavaScript are actually data. This is an important concept that we'll need later on. This means that you can create a function and assign it to a variable:

var f = function () {

return 1;

};

This way of defining a function is sometimes referred to as function literal notation.

The part function () { return 1; } is a function expression. A function expression can optionally have a name, in which case it becomes a named function expression (NFE). So, this is also allowed, although rarely seen in practice (and causes IE to mistakenly create two variables in the enclosing scope: f and myFunc):

var f = function myFunc() {

return 1;

};

As you can see, there's no difference between a named function expression and a function declaration. But they are, in fact, different. The only way to distinguish between the two is to look at the context in which they are used. Function declarations may only appear in program code (in a body of another function or in the main program). You'll see many more examples of functions later on in the book that will clarify these concepts.

When you use the typeof operator on a variable that holds a function value, it returns the string "function":

> function define() {

return 1;

}

> var express = function () {

return 1;

};

> typeof define;

"function"

> typeof express;

"function"

So, JavaScript functions are data, but a special kind of data with two important features:

· They contain code

· They are executable (they can be invoked)

As you have seen before, the way to execute a function is by adding parentheses after its name. As the next example demonstrates, this works regardless of how the function was defined. In the example, you can also see how a function is treated as a regular value: it can be copied to a different variable:

> var sum = function (a, b) {

return a + b;

};

> var add = sum;

> typeof add;

function

> add(1, 2);

3

Because functions are data assigned to variables, the same rules for naming functions apply as for naming variables—a function name cannot start with a number and it can contain any combination of letters, numbers, the underscore character, and the dollar sign.

Anonymous functions

As you now know, there exists a function expression syntax where you can have a function defined like this:

var f = function (a) {

return a;

};

This is also often called an anonymous function (as it doesn't have a name), especially when such a function expression is used even without assigning it to a variable. In this case, there can be two elegant uses for such anonymous functions:

· You can pass an anonymous function as a parameter to another function. The receiving function can do something useful with the function that you pass.

· You can define an anonymous function and execute it right away.

Let's see these two applications of anonymous functions in more detail.

Callback functions

Because a function is just like any other data assigned to a variable, it can be defined, copied, and also passed as an argument to other functions.

Here's an example of a function that accepts two functions as parameters, executes them, and returns the sum of what each of them returns:

function invokeAdd(a, b) {

return a() + b();

}

Now let's define two simple additional functions (using a function declaration pattern) that only return hardcoded values:

function one() {

return 1;

}

function two() {

return 2;

}

Now you can pass those functions to the original function, invokeAdd(), and get the result:

> invokeAdd(one, two);

3

Another example of passing a function as a parameter is to use anonymous functions (function expressions). Instead of defining one() and two(), you can simply do the following:

> invokeAdd(function () {return 1; }, function () {return 2; });

3

Or, you can make it more readable as shown in the following code:

> invokeAdd(

function () { return 1; },

function () { return 2; }

);

3

Or, you can do the following:

> invokeAdd(

function () {

return 1;

},

function () {

return 2;

}

);

3

When you pass a function, A, to another function, B, and then B executes A, it's often said that A is a callback function. If A doesn't have a name, then you can say that it's an anonymous callback function.

When are callback functions useful? Let's see some examples that demonstrate the benefits of callback functions, namely:

· They let you pass functions without the need to name them (which means there are fewer variables floating around)

· You can delegate the responsibility of calling a function to another function (which means there is less code to write)

· They can help with performance

Callback examples

Take a look at this common scenario: you have a function that returns a value, which you then pass to another function. In our example, the first function, multiplyByTwo(), accepts three parameters, loops through them, multiplies them by two, and returns an array containing the result. The second function, addOne(), takes a value, adds one to it, and returns it:

function multiplyByTwo(a, b, c) {

var i, ar = [];

for (i = 0; i < 3; i++) {

ar[i] = arguments[i] * 2;

}

return ar;

}

function addOne(a) {

return a + 1;

}

Let's test these functions:

> multiplyByTwo(1, 2, 3);

[2, 4, 6]

> addOne(100);

101

Now let's say you want to have an array, myarr, that contains three elements, and each of the elements is to be passed through both functions. First, let's start with a call to multiplyByTwo():

> var myarr = [];

> myarr = multiplyByTwo(10, 20, 30);

[20, 40, 60]

Now loop through each element, passing it to addOne():

> for (var i = 0; i < 3; i++) {

myarr[i] = addOne(myarr[i]);

}

> myarr;

[21, 41, 61]

As you can see, everything works fine, but there's room for improvement. For example: there were two loops. Loops can be expensive if they go through a lot of repetitions. You can achieve the same result with only one loop. Here's how to modify multiplyByTwo() so that it accepts a callback function and invokes that callback on every iteration:

function multiplyByTwo(a, b, c, callback) {

var i, ar = [];

for (i = 0; i < 3; i++) {

ar[i] = callback(arguments[i] * 2);

}

return ar;

}

By using the modified function, all the work is done with just one function call, which passes the start values and the callback function:

> myarr = multiplyByTwo(1, 2, 3, addOne);

[3, 5, 7]

Instead of defining addOne(), you can use an anonymous function, therefore saving an extra global variable:

> multiplyByTwo(1, 2, 3, function (a) {

return a + 1;

});

[3, 5, 7]

Anonymous functions are easy to change should the need arise:

> multiplyByTwo(1, 2, 3, function (a) {

return a + 2;

});

[4, 6, 8]

Immediate functions

So far, we have discussed using anonymous functions as callbacks. Let's see another application of an anonymous function: calling a function immediately after it's defined. Here's an example:

(

function () {

alert('boo');

}

)();

The syntax may look a little scary at first, but all you do is simply place a function expression inside parentheses followed by another set of parentheses. The second set says "execute now" and is also the place to put any arguments that your anonymous function might accept:

(

function (name) {

alert('Hello ' + name + '!');

}

)('dude');

Alternatively, you can move the closing of the first set of parentheses to the end. Both of these work:

(function () {

// ...

}());

// vs.

(function () {

// ...

})();

One good application of immediate (self-invoking) anonymous functions is when you want to have some work done without creating extra global variables. A drawback, of course, is that you cannot execute the same function twice. This makes immediate functions best suited for one-off or initialization tasks.

An immediate function can also optionally return a value if you need one. It's not uncommon to see code that looks like the following:

var result = (function () {

// something complex with

// temporary local variables...

// ...

// return something;

}());

In this case, you don't need to wrap the function expression in parentheses, you only need the parentheses that invoke the function. So, the following also works:

var result = function () {

// something complex with

// temporary local variables

// return something;

}();

This syntax works, but may look slightly confusing: without reading the end of the function, you don't know if result is a function or the return value of the immediate function.

Inner (private) functions

Bearing in mind that a function is just like any other value, there's nothing that stops you from defining a function inside another function:

function outer(param) {

function inner(theinput) {

return theinput * 2;

}

return 'The result is ' + inner(param);

}

Using a function expression, this can also be written as:

var outer = function (param) {

var inner = function (theinput) {

return theinput * 2;

};

return 'The result is ' + inner(param);

};

When you call the global function outer(), it will internally call the local function inner(). Since inner() is local, it's not accessible outside outer(), so you can say it's a private function:

> outer(2);

"The result is 4"

> outer(8);

"The result is 16"

> inner(2);

ReferenceError: inner is not defined

The benefits of using private functions are as follows:

· You keep the global namespace clean (less likely to cause naming collisions)

· Privacy—you expose only the functions you decide to the "outside world", keeping to yourself functionality that is not meant to be consumed by the rest of the application

Functions that return functions

As mentioned earlier, a function always returns a value, and if it doesn't do it explicitly with return, then it does so implicitly by returning undefined. A function can return only one value, and this value can just as easily be another function:

function a() {

alert('A!');

return function () {

alert('B!');

};

}

In this example, the function a() does its job (says A!) and returns another function that does something else (says B!). You can assign the return value to a variable and then use this variable as a normal function:

> var newFunc = a();

> newFunc();

Here, the first line will alert A! and the second will alert B!.

If you want to execute the returned function immediately without assigning it to a new variable, you can simply use another set of parentheses. The end result will be the same:

> a()();

Function, rewrite thyself!

Because a function can return a function, you can use the new function to replace the old one. Continuing with the previous example, you can take the value returned by the call to a() to overwrite the actual a() function:

> a = a();

The above alerts A!, but the next time you call a() it alerts B!. This is useful when a function has some initial one-off work to do. The function overwrites itself after the first call in order to avoid doing unnecessary repetitive work every time it's called.

In the preceding example, the function was redefined from the outside—the returned value was assigned back to the function. But, the function can actually rewrite itself from the inside:

function a() {

alert('A!');

a = function () {

alert('B!');

};

}

If you call this function for the first time, it will:

· Alert A! (consider this as being the one-off preparatory work)

· Redefine the global variable a, assigning a new function to it

Every subsequent time that the function is called, it will alert B!

Here's another example that combines several of the techniques discussed in the last few sections of this chapter:

var a = (function () {

function someSetup() {

var setup = 'done';

}

function actualWork() {

alert('Worky-worky');

}

someSetup();

return actualWork;

}());

In this example:

· You have private functions: someSetup() and actualWork().

· You have an immediate function: an anonymous function that calls itself using the parentheses following its definition.

· The function executes for the first time, calls someSetup(), and then returns a reference to the variable actualWork, which is a function. Notice that there are no parentheses in the return statement, because you're returning a function reference, not the result of invoking this function.

· Because the whole thing starts with var a =, the value returned by the self-invoked function is assigned to a.

If you want to test your understanding of the topics just discussed, answer the following questions. What will the preceding code alert when:

· It is initially loaded?

· You call a() afterwards?

These techniques could be really useful when working in the browser environment. Different browsers can have different ways of achieving the same result. If you know that the browser features won't change between function calls, you can have a function determine the best way to do the work in the current browser, then redefine itself so that the "browser capability detection" is done only once. You'll see concrete examples of this scenario later in this book.

Closures

The rest of the chapter is about closures (what better way to close a chapter?). Closures can be a little hard to grasp initially, so don't feel discouraged if you don't "get it" during the first read. You should go through the rest of the chapter and experiment with the examples on you own, but if you feel you don't fully understand the concept, you can come back to it later when the topics discussed previously in this chapter have had a chance to sink in.

Before moving on to closures, let's first review and expand on the concept of scope in JavaScript.

Scope chain

As you know, in JavaScript, there is no curly braces scope, but there is function scope. A variable defined in a function is not visible outside the function, but a variable defined in a code block (for example an if or a for loop) is visible outside the block:

> var a = 1;

> function f() {

var b = 1;

return a;

}

> f();

1

> b;

ReferenceError: b is not defined

The variable a is in the global space, while b is in the scope of the function f(). So:

· Inside f(), both a and b are visible

· Outside f(), a is visible, but b is not

If you define a function inner() nested inside outer(), inner() will have access to variables in its own scope, plus the scope of its "parents". This is known as a scope chain, and the chain can be as long (deep) as you need it to be:

var global = 1;

function outer() {

var outer_local = 2;

function inner() {

var inner_local = 3;

return inner_local + outer_local + global;

}

return inner();

}

Let's test that inner() has access to all variables:

> outer();

6

Breaking the chain with a closure

Let's introduce closures with an illustration. Let's look at this code and see what's happening there:

var a = "global variable";

var F = function () {

var b = "local variable";

var N = function () {

var c = "inner local";

};

};

First, there is the global scope G. Think of it as the universe, as if it contains everything:

Breaking the chain with a closure

It can contain global variables such as a1 and a2 and global functions such as F:

Breaking the chain with a closure

Functions have their own private space and can use it to store other variables such as b and inner functions such as N (for iNNer). At some point, you end up with a picture like this:

Breaking the chain with a closure

If you're at point a, you're inside the global space. If you're at point b, which is inside the space of the function F, then you have access to the global space and to the F space. If you're at point c, which is inside the function N, then you can access the global space, theF space, and the N space. You cannot reach from a to b, because b is invisible outside F. But, you can get from c to b if you want, or from N to b. The interesting part—the closure effect—happens when somehow N breaks out of F and ends up in the global space:

Breaking the chain with a closure

What happens then? N is in the same global space as a. And, as functions remember the environment in which they were defined, N will still have access to the F space, and hence can access b. This is interesting, because N is where a is and yet N does have access to b, but a doesn't.

And how does N break the chain? By making itself global (omitting var) or by having F deliver (or return) it to the global space. Let's see how this is done in practice.

Closure #1

Take a look at this function, which is the same as before, only F returns N and also N returns b, to which it has access via the scope chain:

var a = "global variable";

var F = function () {

var b = "local variable";

var N = function () {

var c = "inner local";

return b;

};

return N;

};

The function F contains the variable b, which is local, and therefore inaccessible from the global space:

> b;

ReferenceError: b is not defined

The function N has access to its private space, to the F() function's space, and to the global space. So, it can see b. Since F() is callable from the global space (it's a global function), you can call it and assign the returned value to another global variable. The result: a new global function that has access to the F() function's private space:

> var inner = F();

> inner();

"local variable"

Closure #2

The final result of the next example will be the same as the previous example, but the way to achieve it is a little different. F() doesn't return a function, but instead it creates a new global function, inner(), inside its body.

Let's start by declaring a placeholder for the global function-to-be. This is optional, but it's always good to declare your variables. Then, you can define the function F()as follows:

var inner; // placeholder

var F = function () {

var b = "local variable";

var N = function () {

return b;

};

inner = N;

};

Now what happens if you invoke F()?:

> F();

A new function, N(),is defined inside F() and assigned to the global inner. During definition time, N() was inside F(), so it had access to the F() function's scope. inner() will keep its access to the F() function's scope, even though it's part of the global space:

> inner();

"local variable".

A definition and closure #3

Every function can be considered a closure. This is because every function maintains a secret link to the environment (the scope) in which it was created. But, most of the time this scope is destroyed unless something interesting happens (as shown above) that causes this scope to be maintained.

Based on what you've seen so far, you can say that a closure is created when a function keeps a link to its parent scope even after the parent has returned. And, every function is a closure because, at the very least, every function maintains access to the global scope, which is never destroyed.

Let's see one more example of a closure, this time using the function parameters. Function parameters behave like local variables to this function, but they are implicitly created (you don't need to use var for them). You can create a function that returns another function, which in turn returns its parent's parameter:

function F(param) {

var N = function () {

return param;

};

param++;

return N;

}

You use the function like this:

> var inner = F(123);

> inner();

124

Notice how param++ was incremented after the function was defined and yet, when called, inner() returned the updated value. This demonstrates that the function maintains a reference to the scope where it was defined, not to the variables and their values found in the scope during the function definition.

Closures in a loop

Let's take a look at a canonical rookie mistake when it comes to closures. It can easily lead to hard-to-spot bugs, because on the surface, everything looks normal.

Let's loop three times, each time creating a new function that returns the loop sequence number. The new functions will be added to an array and the array is returned at the end. Here's the function:

function F() {

var arr = [], i;

for (i = 0; i < 3; i++) {

arr[i] = function () {

return i;

};

}

return arr;

}

Let's run the function, assigning the result to the array arr:

> var arr = F();

Now you have an array of three functions. Let's invoke them by adding parentheses after each array element. The expected behavior is to see the loop sequence printed out: 0, 1, and 2. Let's try:

> arr[0]();

3

> arr[1]();

3

> arr[2]();

3

Hmm, not quite as expected. What happened here? All three functions point to the same local variable i. Why? The functions don't remember values, they only keep a link (reference) to the environment where they were created. In this case, the variable i happens to live in the environment where the three functions were defined. So, all functions, when they need to access the value, reach back to the environment and find the most current value of i. After the loop, the i variable's value is 3. So, all three functions point to the same value.

Why three and not two is another good question to think about for better understanding the for loop.

So, how do you implement the correct behavior? The answer is to use another closure:

function F() {

var arr = [], i;

for (i = 0; i < 3; i++) {

arr[i] = (function (x) {

return function () {

return x;

};

}(i));

}

return arr;

}

This gives you the expected result:

> var arr = F();

> arr[0]();

0

> arr[1]();

1

> arr[2]();

2

Here, instead of just creating a function that returns i, you pass the i variable's current value to another immediate function. In this function, i becomes the local value x, and x has a different value every time.

Alternatively, you can use a "normal" (as opposed to an immediate) inner function to achieve the same result. The key is to use the middle function to "localize" the value of i at every iteration:

function F() {

function binder(x) {

return function () {

return x;

};

}

var arr = [], i;

for (i = 0; i < 3; i++) {

arr[i] = binder(i);

}

return arr;

}

Getter/setter

Let's see two more examples of using closures. The first one involves the creation of getter and setter functions. Imagine you have a variable that should contain a specific type of values or a specific range of values. You don't want to expose this variable because you don't want just any part of the code to be able to alter its value. You protect this variable inside a function and provide two additional functions: one to get the value and one to set it. The one that sets it could contain some logic to validate a value before assigning it to the protected variable. Let's make the validation part simple (for the sake of keeping the example short) and only accept number values.

You place both the getter and the setter functions inside the same function that contains the secret variable so that they share the same scope:

var getValue, setValue;

(function () {

var secret = 0;

getValue = function () {

return secret;

};

setValue = function (v) {

if (typeof v === "number") {

secret = v;

}

};

}());

In this case, the function that contains everything is an immediate function. It defines setValue() and getValue() as global functions, while the secret variable remains local and inaccessible directly:

> getValue();

0

> setValue(123);

> getValue();

123

> setValue(false);

> getValue();

123

Iterator

The last closure example (also the last example in the chapter) shows the use of a closure to accomplish an iterator functionality.

You already know how to loop through a simple array, but there might be cases where you have a more complicated data structure with different rules as to what the sequence of values has. You can wrap the complicated "who's next" logic into an easy-to-use next()function. Then, you simply call next() every time you need the consecutive value.

For this example, let's just use a simple array and not a complex data structure. Here's an initialization function that takes an input array and also defines a secret pointer, i, that will always point to the next element in the array:

function setup(x) {

var i = 0;

return function () {

return x[i++];

};

}

Calling the setup() function with a data array will create the next() function for you:

> var next = setup(['a', 'b', 'c']);

From there it's easy and fun: calling the same function over and over again gives you the next element:

> next();

"a"

> next();

"b"

> next();

"c"

Summary

You have now completed the introduction to the fundamental concepts related to functions in JavaScript. You've been laying the groundwork that will allow you to quickly grasp the concepts of object-oriented JavaScript and the patterns used in modern JavaScript programming. So far, we've been avoiding the OO features, but as you have reached this point in the book, it's only going to get more interesting from here on in. Let's take a moment and review the topics discussed in this chapter:

· The basics of how to define and invoke (call) a function using either a function declaration syntax or a function expression

· Function parameters and their flexibility

· Built-in functions—parseInt(), parseFloat(), isNaN(), isFinite(), and eval()—and the four functions to encode/decode a URL

· The scope of variables in JavaScript—no curly braces scope, variables have only function scope and the scope chain

· Functions as data—a function is like any other piece of data that you assign to a variable and a lot of interesting applications follow from this, such as:

· Private functions and private variables

· Anonymous functions

· Callbacks

· Immediate functions

· Functions overwriting themselves

· Closures

Exercises

1. Write a function that converts a hexadecimal color, for example blue (#0000FF), into its RGB representation rgb(0, 0, 255). Name your function getRGB() and test it with the following code. Hint: treat the string as an array of characters:

2. > var a = getRGB("#00FF00");

3. > a;

4. "rgb(0, 255, 0)"

5. What do each of these lines print in the console?

6. > parseInt(1e1);

7. > parseInt('1e1');

8. > parseFloat('1e1');

9. > isFinite(0/10);

10.> isFinite(20/0);

> isNaN(parseInt(NaN));

11. What does this following code alert?

12.var a = 1;

13.

14.function f() {

15. function n() {

16. alert(a);

17. }

18. var a = 2;

19. n();

20.}

21.

f();

22. All these examples alert "Boo!". Can you explain why?

· Example 1:

· var f = alert;

eval('f("Boo!")');

· Example 2:

· var e;

· var f = alert;

eval('e=f')('Boo!');

· Example 3:

· (function(){

· return alert;}

)()('Boo!');