Chapter 2. Functions

One of JavaScript's best features is the language's implementation of functions. Whereas other languages present different function types for different purposes, JavaScript only has one function type that covers all use cases—from subroutines to lambdas to object methods.

A JavaScript function may look simple on the outside but don't be fooled—the architecture that hides underneath a basic function declaration is quite complex. And while topics like function forms, scope, context, and function execution may seem too complicated for practical consideration, learning about these details that usually go unnoticed improves your knowledge of the language and provides you with an arsenal to solve even the most complex of problems.

There won't be much mention of MooTools in this chapter or the one that follows, so don't be surprised! Instead, we'll be turning our focus on the two essential features of the JavaScript language—functions and objects—and what we learn in these chapters will not only help us understand the MooTools framework but will also assist us further on in developing complex applications.

The Function

Let's start by agreeing on some terms. From here on, we'll define a function as a separate block of code that performs a certain action and returns a value. It can receive arguments, which are values passed to the function, it can be used to compute the resulting return value, and it can be executed multiple times by invoking it.

// a basic function with two arguments:
function add(one, two){
    return one + two;
};

// invoking the function and passing arguments:
var result = add(1, 42);
console.log(result); // 43

// invoking the function again, but with different arguments:
result = add(5, 20);
console.log(result); // 25

JavaScript is a language with first-class functions. A first-class function is a function that can be stored in variables, passed as arguments to other functions, and even be used as return values for other functions. This is possible because functions, like almost everything else in JavaScript, are objects. The language also lets you create new functions and transform defined functions at runtime, which, as we'll see later on, enables MooTools to add improvements to native JavaScript.

One Function, Multiple Forms

While there is only one function type in JavaScript, there are multiple function forms, which are the different ways to create a function. The base syntax for most of these forms is called a function literal and it looks like this:

function Identifier(FormalParameters, ...){
    FunctionBody
}

First is the function keyword followed by a space and an optional identifier that references your function; next comes an optional comma-separated list of formal parameters wrapped in a pair of parentheses, which are turned into local variables that will be available from inside of your function; and finally, you have the optional function body where you'll write statements and expressions. Take note that those are not typos: a function has a lot of optional parts. We won't elaborate on why these parts are optional right now, but we'll learn more about them throughout the chapter.

Note

You'll see the term literal in several parts of this book. In JavaScript, literals are values defined directly from your code. "mark", 1, and true are examples of string, number, and Boolean literals, while function(){} and [1, 2] are function and array literals respectively.

A function is called using the invocation operator () appended to the identifier (or, as we'll see later, to the object itself). The invocation operator can also be used to pass in actual arguments or values for the function's use.

Note

The formal parameters of a function refer to the named variables you declare inside the parenthesis when you create your function, while the actual arguments refer to the values you pass when you invoke a function.

Because functions are objects, they also have methods and properties. We'll talk more about methods and properties of objects in Chapter 3, but for now, let's remember that a function has two basic properties:

  • name – contains the string value of the function's identifier;

  • length – is an integer corresponding to the number of formal parameters defined for the function (or 0 if there are no formal parameters).

Function Declaration

From the base syntax, we can create the first function form, called a function declaration. A function declaration is the simplest of all function forms, and most developers use this form for their code. The following code defines a new function called add:

// a function named `add`
function add(a, b){
    return a + b;
};

console.log(typeof add);    // 'function'
console.log(add.name);      // 'add'
console.log(add.length);    // 2

console.log(add(20, 5));    // 25

The identifier in a function declaration is required, and it will be used to create a variable in the current scope whose value is the function. In our example, an add variable is created in the global scope with the name property of add, equivalent to the function identifier, and the length property is 2 because we have two formal parameters.

Because JavaScript is lexically scoped, identifiers are scoped based on where they are defined rather than on their syntax or where they are executed. This is important to remember because JavaScript allows us to define functions inside other functions and scoping rules might get confusing:

// outer function, global scope
function outer(){

    // inner function, local scope
    function inner(){
        // ...
    };

};

// check the outer function
console.log(typeof outer);  // 'function'

// run outer to create the new functions
outer();

// check the inner function
console.log(typeof inner);  // 'undefined'

In this example, an outer variable is created in the global scope and given the value of our outer function. When it is invoked, the outer function creates a local variable called inner that is given the value of our inner function. When we check the values using the typeof operator, the outer function appears available in the global scope but the inner function is available only from inside the outer function—because the inner function is stored in a local variable.

Because a function declaration also creates a variable with the same name as its identifier, you have to make sure that there are no variables with the same name as the identifier in your current scope. Otherwise, it'll override the value of that variable with the function:

// a variable in the current scope
var items = 1;

// a function declaration with the
// same name; overrides value
function items(){
    // ...
};
console.log(typeof items); // 'function', not 'number'

We'll learn more about the details of JavaScript's scoping in a while, so let's first take a look at other function forms.

Function Expression

The next form takes advantage of the fact that functions can be stored in variables. This form is called a function expression because rather than explicitly defining a function, you "express" a function as a value of a variable.

Here's the same add function we declared above, but using a function expression.

var add = function(a, b){
    return a + b;
};

console.log(typeof add);    // 'function'
console.log(add.name);      // '' or 'anonymous'
console.log(add.length);    // 2

console.log(add(20, 5));    // 25

In this example, we create a function literal that becomes the value of our variable add. We can then use this variable to invoke our function, as illustrated on the last line where we use the function to add two numbers.

You'll notice that the length property of the function is the same as its function declaration counterpart, but the name property is different. In some JavaScript interpreters, its value will be a blank string (''), while in others it'll be 'anonymous'. This happens because we didn't specify an identifier for the function literal. In JavaScript, a function without an explicit identifier is called an anonymous function.

The scoping rules for function expressions are a bit different from function declarations because they depend on variable scoping. Remember that in JavaScript, the var keyword defines a variable to be scoped locally, and omitting the keyword creates a global variable instead:

// outer function, global scope
var outer = function(){

    // inner function, local scope
    var localInner = function(){
        // ...
    };

    // inner function, global scope
    globalInner = function(){
        // ...
    };

};

// check the outer function
console.log(typeof outer);          // 'function'
// run outer to create the new functions
outer();

// check the new functions
console.log(typeof localInner);     // 'undefined'
console.log(typeof globalInner);    // 'function'

The function outer is defined to be of global scope, because while we use the var keyword, it's on the top level of the application. Inside the function are two other functions, localInner and globalInner. The localInner function is stored in a variable that's local to the inside of the outer function and can't be accessed in the global scope. However, globalInner is stored in a variable that's defined without the var keyword, making both the variable and the function it contains global.

Named Function Expression

Although function expressions are usually written using anonymous functions, you can also specify an explicit identifier for your function. This is a variation of the function expression called a named function expression.

var add = function add(a, b){
    return a + b;
};

console.log(typeof add);    // 'function'
console.log(add.name);      // 'add'
console.log(add.length);    // 2

console.log(add(20, 5));    // 25

This example is the same as a function expression that uses an anonymous function, but we specify an identifier for the function literal. Unlike in the previous example, the name property of this function is 'add', which is consistent with the identifier we specified, rather than 'anonymous' or an empty string.

JavaScript allows an explicit identifier for function expressions so that a function can reference itself from the inside. You might be asking why you'd need this feature, so let's look at two different examples.

var myFn = function(){
    // reference the function
    console.log(typeof myFn);
};

myFn(); // 'function'

In the example above, the function myFn could easily reference itself via the variable holding it because the variable that contains the function is available inside the function scope. However, consider the next example:

// global scope
var createFn = function(){

    // result function
    return function(){
        console.log(typeof myFn);
    };

};
// different scope
(function(){

    // put the result function of `createFn`
    // into a local variable
    var myFn = createFn();

    // check if reference is available
    myFn(); // 'undefined'

})();

This example might be a little too complex, but we'll tackle the details later. Right now, just focus on the functions. In our global scope, we create a new function called createFn, which returns a new logging function like our previous example. Next, we create a new localized scope and define a variable myFn and assign the return value of createFn.

The code is similar to the earlier example, but here we use the function value that's returned from another function instead of directly assigning the function literal to the variable. Also, the variable myFn is on a different localized scope, which is not accessible to our resulting function value. Thus, it'll log 'undefined' rather than 'function' in this case, because the scoping doesn't allow the function to reference itself via the variable holding it.

By adding an explicit identifier to our result function, we'll be able to reference the function itself even if we don't have access to the variable holding it:

// global scope
var createFn = function(){

    // result function, with identifier
    return function myFn(){
        console.log(typeof myFn);
    };

};

// a different scope
(function(){

    // put the result function of `createFn`
    // into a local variable
    var myFn = createFn();

    // check if reference is available
    myFn(); // 'function'

})();

Adding an explicit identifier is like creating a new variable that's available from inside the function that can be used to reference the function itself, making it possible for the function to call itself from the inside (for recursive operations) or perform actions on itself.

A named function declaration has the same scoping rules as a function declaration with an anonymous function: the scope of the variable determines whether the function will be local or global. However, the additional identifier has a different scoping rule: it's only available from inside the function.

// a function with different identifiers
var myFn = function fnID(){
    console.log(typeof fnID);
};

// the variable
console.log(typeof myFn);   // 'function'

// the identifier
console.log(typeof fnID);   // 'undefined'

myFn(); // 'function'

This example shows that while the variable myFn could be used to reference the function, the identifier fnID isn't accessible from the outside. However, accessing this identifier variable from the inside of the function itself works.

Single-Execution Function

We touched on the subject of anonymous functions in passing when creating function expressions, but they have much broader use than that. One of the most important is a technique that uses an anonymous function to create a function that's executed immediately, without storing references to it. This form is called a single-execution function.

// create a function and invoke it immediately
(function(){

    var msg = 'Hello World';
    console.log(msg); // 'Hello World'

})();

Here we create a function literal and wrap it inside a pair of parentheses. We then use the function invocation operator ( ) to execute the function immediately. The function isn't stored in a variable, nor is any reference to it created. It's a "run-once" function: create it, do whatever it does, and then move on.

To understand how a single-execution function works, you need to remember that functions are objects and objects are values. Because JavaScript values can be used immediately without having to store them in variables, you can create anonymous functions that you immediately execute just by appending a function invocation operator.

However, notice that we wrap our function inside a pair of parentheses in the previous example, instead of doing it like this:

// this is considered a syntax error
function(){

    var msg = 'Hello World';
    console.log('msg'), // 'Hello World'

}();

A JavaScript interpreter will throw a syntax error when it encounters these lines because it interprets the code as a function declaration. It sees a function literal but no identifier, and it throws an error because a function declaration requires an identifier to follow the function keyword.

We need to wrap the function in parentheses in order to tell the JavaScript interpreter that it is not a function declaration but, rather, that we are creating a function and we use its value immediately. Because we have no identifier we can use to reference the function, we need to wrap it in parentheses in order to create a direct reference to the function and be able to directly call it. This wrapping in parentheses is needed only when we have no direct reference to the function, like with single-execution functions.

Note

The invocation operator can be included within the parentheses or outside it, like so: (function(){... }()). Putting the operator outside is more common, though, and it's considered as the proper MooTools style.

A single-execution function is useful in a lot of cases and the most important of these is to keep variables and identifiers inside a localized, protected scope. Consider the following example:

// top level scope
var a = 1;

// localize scope with a single
// execution function
(function(){

    // local scope
    var a = 2;

})();

console.log(a); // 1

Here, our first variable a is declared in the top scope, making it available globally. We then create a single execution function and redeclare a inside, changing its value to 2. But because this is a localized variable, the original top-level a variable does not change.

This technique is popular, especially with library developers, because localizing variables into a separate scope avoids identifier clashing. If you include two scripts that define the same identifier within your application, the chance of one of them overwriting the value of the other is high—unless one of them localizes their scope via a single-execution function.

Another way of using a single-execution function is when you want to perform a task with a function and use its return value in a throwaway function:

// Store a single-execution function's
// return value to a variable
var name = (function(name){

    return ['Hello', name].join(' '),

})('Mark'),

console.log(name); // 'Hello Mark'

Don't get confused by this code: this is not a function expression. What's happening is that we create a single-execution function that's immediately invoked and returns the value we want to store in our variable.

Another feature of single-execution functions is their ability to have an identifier, just like with a function declaration:

(function myFn(){

    console.log(typeof myFn); // 'function'

})();

console.log(typeof myFn); // 'undefined'

While it may seem like this is a function declaration, it's actually a single-execution function. Even though we specify an identifier for the function, it does not create a variable in the current scope as a function declaration does. This lets you reference the function from inside itself without creating a new variable inside the current scope. This is especially useful to prevent overwriting the original values of variables that already exist in the current scope.

Like any other function, single-execution functions can receive arguments passed via the invocation operator. Combine this with an identifier available from inside the function and the ability to store the return value of a single-execution function and you can create quick recursive functions for your code:

var number = 12;

var numberFactorial = (function factorial(number){
    return (number == 0) ? 1 : number * factorial(number - 1);
})(number);

console.log(numberFactorial); // 479001600

Function Object

The last function form, the function object, is different from all the rest because it does not use a function literal. The basic syntax of this form is as follows:

// a function object
new Function('FormalArgument1', 'FormalArgument2', ..., 'FunctionBody'),

Here, we use the Function constructor to create a new function by passing strings as arguments. The first arguments define the named arguments for the function, and the last argument defines the function body.

Note

While we call this form a function object, remember that all functions are objects. We simply use this term to differentiate between a function created via a literal and one created via an object constructor, which will be discussed in the next chapter.

Here's our add function using this form:

var add = new Function('a', 'b', 'return a + b;'),

console.log(typeof add);    // 'function'
console.log(add.name);      // '' or 'anonymous'
console.log(add.length);    // 2

console.log(add(20, 5));    // 25

You'll notice that the code is similar to using an anonymous function literal. Like an anonymous function, a function object has either a blank string or 'anonymous' for its name property value. In the first line, we create a new function using the Function constructor, passing in the arguments 'a', 'b', and 'return a + b;'. The first two strings will become the named arguments of the function, and the final string will become the function body. Using this form is like using eval: the last string argument is turned into executable JavaScript code and used as the body of the function.

Note

You don't need to pass the named arguments as separate strings. The Function constructor also allows for a single string containing comma-separated name values, like so: new Function('a, b', 'return a + b;'),

While this form has its uses, as we'll see in later in this book where it'll be used as a templating engine, a Function object has a disadvantage over a function literal because the function's scope is limited to the global scope:

// global variable
var x = 1;

// localized scope
(function(){

    // local x variable
    var x = 5;

    // a function object
    var myFn = new Function('console.log(x);'),
    myFn(); // 1, not 5.

})();

Even though we have a local variable x in our separate scope, the function object will not be able to reference this because it's evaluated in the global scope.

Arguments

All functions have access to their formal arguments from the inside. These formal arguments are turned into local variables within the function and their values correspond to the values passed when the function was invoked. The mapping of arguments is based on the order they were passed: the first value corresponds to the first named argument and so on.

When the number of actual arguments passed is greater than the number of formal arguments, the additional actual arguments are not stored in any formal argument variable. On the other hand, if the number of actual arguments passed is less than the defined formal arguments, the remaining formal arguments will have the value of undefined.

var myFn = function(first, second){
    console.log('first: ' + first);
    console.log('second: ' + second);
};

myFn(1, 2);
// first: 1
// second: 2

myFn('a', 'b', 'c'),
// first: a
// second: b

myFn('test'),
// first: test
// second: undefined

Because JavaScript allows a function to receive a mutable number of arguments, it also provides a way to access the arguments passed to the function even if there are no corresponding formal arguments defined. This is done via the arguments object, which is an array-like object that contains the values of all actual arguments passed to a function:

var myFn = function(){
    console.log('length: ' + arguments.length);
    console.log('first: ' + arguments[0]);
};

myFn(1, 2);
// length: 2
// first: 1

myFn('a', 'b', 'c'),
// length: 3
// first: a

myFn('test'),
// length: 1
// first: test

The arguments object has a length property that can be used to find out the number of arguments passed to a function. The values of the arguments can be accessed by providing a zero-based index to the arguments object: arguments[0] is the first value passed, arguments[1] is the second value passed, and so on.

By using the arguments object instead of named arguments, you can create functions that take a different number of arguments for processing. For example, we can modify our add function to accept multiple arguments and add them:

var add = function(){
    var result = 0,
        len = arguments.length;
    while (len--) result += arguments[len];
    console.log(result);
};
add(15); // 15
add(31, 12, 92); // 135
add(19, 53, 27, 41, 101); // 241

There is one big problem with the arguments object that you need to remember: it is a mutable object. You can replace the values inside arguments or even change it entirely to another object:

var rewriteArgs = function(){
    arguments[0] = 'no';
    console.log(arguments[0]);
};

rewriteArgs('yes'), // 'no'

var replaceArgs = function(){
    arguments = null;
    console.log(arguments == null);
};

replaceArgs(); // true

The first function shows that we can overwrite the values of the arguments object, and the second function changes the value of the object to null. The only constant item would be the length property of the object: as long as you don't overwrite the arguments object or change its value entirely, the length would still reflect the number of arguments passed even if you append new objects to it:

var appendArg = function(){
    arguments[2] = 'three';
    console.log(arguments.length);
};

appendArg('one', 'two'), // 2

When writing code, take care to ensure you don't overwrite the arguments object or change its values so you don't end up with weird side effects.

There's another property of the arguments object, callee, and it's a reference to the function itself. In the previous section we used the function identifiers to refer to the function, and that's similar to how arguments.callee works:

var number = 12;

var numberFactorial = (function(number){
    return (number == 0) ? 1 : number * arguments.callee(number - 1);
})(number);

console.log(numberFactorial); // 479001600

Notice that the function here is an anonymous one: we have no identifier yet we're able to call it recursively via the arguments.callee property. This is the exact purpose of this property: to enable a function to call itself without using its identifier (if it even has one).

But while it's a useful property, arguments.callee has been deprecated in ECMAScript 5 and using it in ES5 Strict Mode will throw an error. So, if possible, don't use this property; instead use the identifier techniques discussed earlier.

While JavaScript allows for a variable number of arguments to be passed to a function, it does not enable default values. However, you can mimic default argument values by checking the passed values and setting them if they're undefined:

var greet = function(name, greeting){

    // check if arguments are defined;
    // if not, use a default value..
    name = name || 'Mark';
    greeting = greeting || 'Hello';

    console.log([greeting, name].join(' '));
};

greet('Tim', 'Hi'), // 'Hi Tim'
greet('Tim'),       // 'Hello Tim'
greet();            // 'Hello Mark'

Because named arguments that don't have corresponding passed values are given the value of undefined (and thus have a "falsy value" or a value that evaluates to the Boolean false), we can use the logical OR operator (||) to reassign a default value to the variable.

It's also important to remember that native type arguments (such as strings or integers) are passed to a function by value, which means that changes to these values aren't reflected in the outside scope. However, when used as arguments to functions, objects are passed by reference, reflecting any changes inside the function scope:

var obj = {name: 'Mark'};

var changeNative = function(name){
    name = 'Joseph';
    console.log(name);
};

changeNative(obj.name); // 'Joseph'

console.log(obj.name);  // 'Mark'

var changeObj = function(obj){
    obj.name = 'Joseph';
    console.log(obj.name);
};

changeNative(changeObj);      // 'Joseph'

console.log(obj.name);  // 'Joseph'

In the first function, we pass the obj.name as an argument and because it's a native string type, changing it from within the function does not affect the original value. But in our second function, we pass the object itself and the function receives a direct reference to the object, enabling us to change the property, which is reflected outside the function.

Finally, you'll recall that I mentioned that the arguments object is array-like. This means that while the arguments object seems to be like an array (in the sense that its values can be accessed via numeric indices), it's not actually an array and it doesn't have array methods. You can, however, turn the arguments object into a real array using the Array.prototype.slice function:

var argsToArray = function(){
    console.log(typeof arguments.callee); // 'function'
    var args = Array.prototype.slice.call(arguments);
    console.log(typeof args.callee); // 'undefined'
console.log(typeof args.splice); // 'function'
};

argsToArray();

You'll see how this is useful in later sections when we deal with more advanced techniques. For now, just keep in mind that you can turn your arguments object into an array if you need to.

Return Values

The return keyword is used inside a function body to explicitly return a value. JavaScript allows multiple return statements from within the code, and the function exits as soon as one is executed:

var isOne = function(number){
    if (number == 1) return true;

    console.log('Not one..'),
    return false;
};

var one = isOne(1);
console.log(one);
// true

var two = isOne(2);
// 'Not one..'
console.log(two);
// false

The first time we call this function, we pass it the argument 1. This argument meets the condition of our if statement within the function body, so the return statement is executed and the function halts. However, in the second call, the value 2 does not meet the condition so the function continues until the next return statement.

Multiple return statements are useful for limiting the execution of a function, and it's common practice to halt the function at the beginning using variable checks in order to save processing time and prevent errors, as the following snippet of code for getting a data property from a DOM element illustrates:

var getData = function(id){
    if (!id) return null;
    var element = $(id);
    if (!element) return null;
    return element.get('data-name'),
};

console.log(getData());                     // null
console.log(getData('non existent id'));    // null
console.log(getData('main'));               // 'Tim'

Because retrieving an element from the DOM and getting its property are expensive tasks, we place checks within the code to immediately halt further execution in order to save processing power. The second check also functions as a guard to prevent the code from throwing an error when calling the get method of the object if its value is null.

As a final note on return values, remember that all JavaScript functions return values—whether or not you explicitly return one. If you don't specify a return value via an explicit statement or if your return statements are never executed, the return value of the function will be undefined.

Function Internals

While function forms, arguments, and return values are part of the core function topics, there are a lot of things underneath the visible source code that require our attention. In the next sections, we'll take a behind-the-scenes look at the internals of functions as well as a peek at what happens when JavaScript interpreters encounter a function. We won't go into deep technical details, but we'll focus on the most important parts we need to know in order to understand functions.

Some people find parts of JavaScript arbitrary and the rules of the language seem hard to grasp at first. Learning the internals helps a lot in understanding these seemingly random rules, and as we'll see throughout the next sections, knowing the inner workings of JavaScript actually contributes to making your code much more reliable and powerful.

Note

The actual implementation of JavaScript interpreters is mostly creator-dependent, and therefore some details we'll discuss in the next sections may not be true for all JavaScript interpreters. However, the ECMAScript specification does describe general rules on how interpreters should implement functions, so we do have an official guide to function internals.

Executable Code and Execution Contexts

JavaScript differentiates between three kinds of executable code:

  • Global code is the code that's found on the top level of the application source.

  • Function code is the code that's inside functions or what we called before the bodies of functions.

  • Eval code is the code that's passed and executed by the JavaScript function eval().

The following example shows these different kinds of executable code:

// this is global code
var name = 'John';
var age = 20;

function add(a, b){
    // this is function code
    var result = a + b;
    return result;
};

(function(){
    // this is function code
    var day = 'Tuesday';
var time = function(){
        // this is also function code,
        // but it is separate from the code
        // above
        return day;
    };
})();

// this is eval code
eval('alert("yay!");'),

The variables name, age, and most of the functions we created all reside in the top level, which mean they're global code. However, the code inside functions is function code, and it's seen as separate from the global code. In cases where there are functions inside other functions, the content of the inner functions is also treated as separate function code—which is why the code inside the time function is separate.

So why do we have different types of code in JavaScript? In order to keep track of exactly where it is when interpreting code, the JavaScript interpreter uses an internal mechanism called an execution context. During the course of running a script, JavaScript will create and enter several execution contexts, not only to keep track of its location within the program but also to store data that's used for proper execution of the program.

A JavaScript program will have at least one execution context, normally called the global execution context. When a JavaScript interpreter starts executing your program, it "enters" the global execution context and begins interpreting the code using this execution context. When it encounters a function, the interpreter creates a new execution context and then enters this new context and executes the function code using this context. When the function has finished executing or when it has returned a value, the interpreter exits the execution context and returns to the previous one.

This might get confusing, so let's clear it up a bit with a little example.

var a = 1;

var add = function(a, b){
    return a + b;
};

var callAdd = function(a, b){
    return add(a, b);
};

add(a, 2);

callAdd(1, 2);

This code is simple enough to understand, and it's a good example of how JavaScript creates, enters, and leaves execution contexts. Let's go through it step by step:

  1. When the program starts, the JavaScript interpreter enters the global execution context and starts evaluating the code. It creates the variables a, add, and callAdd, and defines their values to be the number 1, a function, and another function, respectively.

  2. The interpreter encounters a function invocation for the add function. It creates a new execution context, enters it, and evaluates the expression a + b, then returns the value of this expression. After it returns the value, it leaves the new execution context it created, discards it, and goes back to the global execution context.

  3. The interpreter then encounters another function invocation, this time for callAdd. Like in step 2, it creates a new execution context and enters it before interpreting the callAdd function body. As it evaluates the contents of the function, though, it encounters another function invocation—to the add function—and as for every other function invocation, the interpreter creates a new context and enters it. At this point, we have three execution contexts: the global execution context, one for callAdd, and another for add, the last one being the active execution context. When the add function is finished, its execution context is discarded and the interpreter enters the execution context of callAdd, which also returns a value, thereby signaling the interpreter to exit and discard this execution context and reenter the global one.

Execution contexts may be a bit confusing but since you'll never actually deal with them directly with your code, it's acceptable if you don't understand them fully at first. Still, a question comes to mind: if we're not gonna deal directly with execution contexts, why do we need to discuss them?

The answer lies in the other uses for execution contexts. I already mentioned that JavaScript interpreters use execution contexts to keep track of their position in the code, but aside from this important use, several internal objects are also associated with execution contexts that directly affect your JavaScript program.

Variables and Variable Instantiation

The first of these internal objects is the variable object. Each execution context has its own variable object that's used to keep track of all the variables that are defined within that context.

The process of creating variables in JavaScript is called variable instantiation. Because JavaScript is a lexically-scoped language, the scope of a variable depends on where it is instantiated in your code. The only exceptions to this rule are global variables created by omitting the var keyword:

var fruit = 'banana';

var add = function(a, b){
    var localResult = a + b;
    globalResult = localResult;
    return localResult;
};

add(1, 2);

In this snippet, the variable fruit and the function add are globally scoped and can be used throughout the whole script. On the other hand, the variables localResult, a, and b are locally scoped and are available only inside the add function. The variable globalResult, however, is globally scoped because the var keyword is omitted.

Variable instantiation is the first thing that happens when a JavaScript interpreter enters an execution context. The interpreter creates a variable object for the execution context and then checks for var declarations in the current context. These variables are then created and added in the variable object and given the value undefined. When we consider this with our example code, we can say that the variables fruit and add are instantiated using the variable object of the global execution context, while the variables localResult, a, and b are instantiated using the variable object of the local execution context of the add function. The variable globalResult, however, is a tricky one, and we'll discuss its implications later.

An important point to remember about variable instantiation is that it's connected with execution contexts in a deeper way. If you recall, we have three types of executable code in JavaScript: global code, function code, and eval code. In turn, we can say we also have three types of execution contexts: the global execution context, function execution contexts, and eval execution contexts. And since variable instantiation uses the variable object of an execution context, it follows that we can have only three main types of variables in JavaScript: global variables, variables that are local to a function, and variables from evaluated code.

This leads us to one of the things that confuse a lot of people about the language: JavaScript has no block scope. In other C-like languages, code inside a pair of curly braces form what is called a block, which has its own separate scope. However, because variable instantiation happens at the level of the execution context, a variable that's instantiated anywhere in a current execution context will be available throughout that context, not just in the current block.

var x = 1;

if (false) {
    var y = 2;
}

console.log(x); // 1
console.log(y); // undefined

In a language that has block scope, the line console.log(y) should produce an error since you're trying to access a variable that's not been instantiated (because the line var y = 2; will never be evaluated). However, JavaScript doesn't throw an error with this code, but instead tells us that the value of y is undefined, which is the value of a variable that's been instantiated but not given a value. Seems like curious behavior, doesn't it?

However, if we remember that variable instantiation happens at the level of the execution context, we'll know that this behavior is expected. When JavaScript interprets the snippet above, it starts by entering the global execution context and then does variable instantiation by looking for all variable declarations throughout the whole context and adds these variables to the variable object. So our code is really interpreted like this:

var x;
var y;

x = 1;

if (false) {
    y = 2;
}

console.log(x); // 1
console.log(y); // undefined

The same context-level instantiation also applies to functions:

function test(){
    console.log(value); // undefined
    var value = 1;
    console.log(value); // 1
};

test();

Even though our variable is defined after the first call to console.log, we still get a log of undefined rather than an error because variable instantiation happens before any other code inside the function is run. Our variable is already instantiated and given the value of undefined before the first line of the function body is executed, but it is only given a value of 1 on the second line. This is why it's always good to put all your variable declarations at the start of your code or at the beginning of a function. By declaring all variables at the beginning, you make it clear that the variable will be available across the whole of the current scope.

As you can see, the process of creating the variable (instantiation) and the process of assigning a value to a variable (declaration) are done separately by the JavaScript interpreter. This leads us back to a previous example:

var add = function(a, b){
    var localResult = a + b;
    globalResult = localResult;
    return localResult;
};

add(1, 2);

In this snippet, the variable localResult is local to the function, but the variable globalResult becomes global. The most common explanation for this is that when you omit the var keyword, the variable will be global, but that's a very naive explanation. Since we know that the processes of variable instantiation and declaration are separate, we can rewrite the function to look like how the interpreter might see it:

var add = function(a, b){
    var localResult;
    localResult = a + b;
    globalResult = localResult;
    return localResult;
};

add(1, 2);

The variable localResult will be instantiated and a reference to it will be stored in the variable object of the execution context. When the interpreter sees the line localResult = a + b;, it checks the variable object of the current execution context to see if there's a variable with the same name stored, and because there is such a variable in our example, the value is assigned to that variable. However, when it executes globalResult = localResult, it does not find any references so it proceeds to check whether the variable is present in the variable object of the previous context (in this case, the global execution context). But because it still does not find a reference to this variable, the interpreter assumes that it's new and creates a new variable in the last execution context it checked—which is always the global execution context. Therefore, the variable becomes a variable of the global execution context.

Scoping and the Scope Chain

That process of looking up variables in an execution context's scope is called identifier resolution and it's powered by another internal object associated with execution contexts, the scope chain. As its name implies, the scope chain is an ordered list containing objects that the JavaScript interpreter uses to figure out which variable a particular identifier is referring to.

Each execution context has its own scope chain that's created before the interpreter enters the execution context. A scope chain can contain several objects, one of which would be the variable object of the current execution context. Let's consider this simple code:

var fruit = 'banana';
var animal = 'cat';

console.log(fruit); // 'banana'
console.log(animal); // 'cat'

The code runs within the global execution context, so the variables fruit and animal are stored in the variable object of the global execution context. When the interpreter encounters the line console.log(fruit), it sees the identifier fruit and looks for the value of this identifier by searching through the current scope chain—which contains a single object, the variable object of the global execution context. The interpreter then figures out that the variable has the value of 'banana'. The same thing happens to the line after that.

Coincidentally, the variable object of the global execution context is used for another purpose, as the global object. This global object has its own internal representation inside the interpreter, but it's also available through JavaScript itself via the window object in the browser or the global object in certain JavaScript interpreters. All global variables are actually members of the global object: in the example above, you can reference the variables fruit and animal via window.fruit or global.fruit and window.animal or global.animal, depending on where you're running the script. The global object is present in all scope chains for all execution contexts, and in the case of global code, the global object is the only object inside the scope chain.

It gets more complicated with functions, though. Aside from the global object, the scope chain of a function also contains the variable object of its own execution context.

var fruit = 'banana';
var animal = 'cat';

function sayFruit(){
    var fruit = 'apple';

    console.log(fruit); // 'apple'
    console.log(animal); // 'cat'
};

console.log(fruit); // 'banana'
console.log(animal); // 'cat'

sayFruit();

For code within the global execution context, the identifiers fruit and animal refer to the variables with the values 'banana' and 'cat' respectively, because those are the references stored in the variable object (i.e., the global object) of the execution context. However, inside the sayFruit function the identifier fruit has a different value because another variable fruit was also declared inside that function. Since the variable object of the current execution context is in the front of the chain before the global object, the interpreter knows that we are referring to a local variable rather than the global one and correctly resolves the identifier.

Since JavaScript is a lexically-scoped language, identifier resolution also respects the position of functions in the code. A function inside another function can see the variables from the outer function, as in this example:

var fruit = 'banana';

function outer(){
    var fruit = 'orange';

    function inner(){
        console.log(fruit); // 'orange'
    };

    inner();
};

outer();

The variable fruit inside the inner function has the value 'orange' because the scope chain of the function not only contains its own variable object but also the variable object of the function where it was declared in the code (in this case, the outer function). When the interpreter encounters the identifier fruit inside the inner function, it first looks at its own variable object. Since there's no such identifier there, it goes to the next object, which is the variable object of the outer function. The interpreter then finds the identifier it needs, so it stops there and concludes that the value of fruit is 'orange'.

That, however, only applies to functions created using function literals. Function objects created using new Function() that are inside other functions behave differently as they won't be able to access the variables from their external function:

var fruit = 'banana';

function outer(){
    var fruit = 'orange';

    var inner = new Function('console.log(fruit);'),

    inner(); // 'banana'

};

outer();

In this example, our inner function wasn't able to access the local variable fruit inside the outer function, so the output of console.log(fruit) inside the inner function is 'banana' rather than 'orange'. This happens because functions created using the new Function() form have scope chains that contain only their own variable objects and the global object. The variable objects of any surrounding functions aren't added to the scope chain of these functions, and this limits scope resolution to only local and global variables.

The creation of the scope chain happens right after the interpreter creates the execution context and before variable instantiation. In the case of global code, the interpreter first creates the global execution context, then the scope chain. It then proceeds to create the variable object of the global execution context (which also becomes the global object), then it does variable instantiation before adding the variable object to the scope chain. In the case of function code, the same thing happens but the global object is added to the function's scope chain first, then the variable objects of surrounding functions (if any), with the function's own scope chain being added last. Since the scope chain is technically a logical stack, the order of lookup during identifier resolution depends on which object was added first, so the most local of variable objects is added last to ensure that the local variable objects would be searched first during identifier resolution.

Closures

The presence of first-class functions in JavaScript and the ability of these functions to reference variables from surrounding functions give the language the base for another powerful function feature: closures. This language feature makes JavaScript functions extra useful, though it's also one of the more difficult to understand parts of the language. But because we already discussed how JavaScript functions work internally in the previous sections, we should be able to figure out how exactly closures work and how we can use them in our code.

Normally, the lifetime of a JavaScript variable is limited by where it was declared. A global variable will persist until the program is finished while a variable local to a function will only be available until the function is done. When the function exits, the local variables are destroyed by the interpreter via garbage collection and are no longer available. However, when an inner function inside another function retains a reference to a variable from the outer function and this inner function is then kept in reference even after the execution of the outer function, the variable persists even though the outer function has finished. When this happens, we get a closure.

Confusing? Let's check some examples:

var fruit = 'banana';

(function(){
    var fruit = 'apple';
    console.log(fruit); // 'apple'
})();

console.log(fruit); // 'banana'

Here, we have a single execution function that creates a variable fruit. Within that function, the value of the variable fruit is 'apple'. When the function is done, the variable fruit with the value of 'apple' is destroyed. We're left with the global variable fruit that has the value 'banana'. No closure was created. Let's take a look at another one.

var fruit = 'banana';

(function(){
    var fruit = 'apple';

    function inner(){
        console.log(fruit); // 'apple'
    };

    inner();
})();

console.log(fruit); // 'banana'

This example is similar to one we saw in another section. The single execution function creates a variable fruit and a function called inner. When the inner function gets called, it references the variable fruit from the outer function and we get the value 'apple' rather than 'banana'. Unfortunately, the inner function is local to the single execution function, which means it also gets destroyed after the function is done. Still no closure, so let's look at one more.

var fruit = 'banana';
var inner;

(function(){
    var fruit = 'apple';

    inner = function(){
        console.log(fruit);
    };

})();

console.log(fruit); // 'banana'
inner(); // 'apple'

And now it gets interesting. In this code we declared a variable called inner in the global scope and, within our single execution function, we gave this global variable the value of a function that logs the value of the fruit variable. Normally, the variable fruit inside the single execution function should be destroyed after the function is done, like in our previous examples, but because we referenced this variable inside our inner function, it is retained, which is why we get the value 'apple' when we call the function. And this is a closure.

A closure is created when a function inside another function gets stored outside the outer function's scope while retaining references to a variable from the outer function. Even though the function no longer operates inside its surrounding function, references to the variables from the surrounding function are still retained because the internal scope chain of the function still contains the variable object of the surrounding function, even though the surrounding function may no longer exist.

Remember that a function's scope chain is tied to its execution context, and like every other object associated with an execution context, it is created right after the creation of the execution context and destroyed together with the execution context when the function exits. Also, the interpreter only creates a function's execution context (and therefore its scope chain) when the function is invoked. In the case of our example above, the inner function is invoked during the last line of our code and, by that time, the execution context (along with its scope chain and variable object) of the original anonymous function has already been destroyed. So how can the inner function reference the local variable fruit inside the anonymous function when the original variable object containing it is already long gone by then?

The answer lies in a function's internal property called the scope property. All JavaScript functions have their own internal scope property that contains references to the objects that will be used to build the scope chain. When the interpreter creates the scope chain for a function, it looks at the function's scope property to see which items to add to the scope chain. Since this scope property is associated with the function itself rather than the execution context, it persists until the function is finally destroyed—making it usable no matter how many times the function is invoked.

A function created in the global context has a scope property that contains the global object, so its scope chain consists only of the global object and its own variable object. A function created inside another function has a scope object that contains all the objects inside the encapsulating function's scope property and the encapsulating function's variable object.

function A(){
    function B(){
        function C(){
        };
    };
};

In this snippet, the A function's scope property contains only the global object. The B function's scope property will inherit the contents of the A function's scope property (in this case, only the global object) plus the variable object of the A function because it's nested inside. Finally, the C function will have a scope property that inherits all of the objects from the B function's scope property—the global object and the variable object of A—plus the preceding function's variable object.

Function objects created with the new Function() form, on the other hand, only have one item in their scope property (which is the global object). This means that they can't access the local variables from surrounding functions, and therefore can't be used to create closures.

The "this" Keyword

We'll wrap up these sections on function internals in a bit, but we have one final item to discuss: the this keyword. If you have experience in other object-oriented programming languages, you might have come across a similar keyword, usually called this or self, that's used to refer to the current instance (more on this in Chapter 3). However, JavaScript's this keyword is a little trickier, since its value is dependent upon the execution context and the caller of the function. It's also mutable, which means its value can be changed during runtime.

The value of this will always be an object, and there are several rules that dictate which object will become the this in a particular piece of code. The simplest rule is that in the global context, this refers to the global object:

var fruit = 'banana';

console.log(fruit); // 'banana'
console.log(this.fruit); // 'banana'

If you recall, all variables that are declared in the global context are actually properties of the global object. Here we see that this.fruit correctly resolves to the fruit variable, showing us that the this keyword in the snippet is in fact the global object. Functions declared in the global context will also have the this keyword pointing to the global object inside their function bodies:

var fruit = 'banana';

function sayFruit(){
    console.log(this.fruit);
};

sayFruit(); // 'banana'
(function(){
    console.log(this.fruit); // 'banana'
})();

var tellFruit = new Function('console.log(this.fruit);'),

tellFruit(); // 'banana'

For functions that are created as properties of objects (often termed methods), the this keyword will refer to the object itself rather than the global object:

var fruit = {

    name: 'banana',

    say: function(){
        console.log(this.name);
    }

};

fruit.say(); // 'banana'

We'll get further into the topic of objects in the next chapter, but for now, notice how the line this.name resolves properly to the name property of the fruit object. In essence, it's the same for previous examples: since the functions in the previous examples were properties of the global object, the this keyword inside the function body referred to the global object. So it follows that functions that are properties of any object will have the object itself as the this value in their body.

Nested functions, on the other hand, follow one simple rule: they always have the global object as their default this value, no matter where they appear:

var fruit = 'banana';

(function(){
    (function(){
        console.log(this.fruit); // 'banana'
    })();
})();

var object = {

    fruit: 'orange',

    say: function(){
        (function(){
            console.log(this.fruit); // 'banana'
        })();
    }

};

object.say();

Here, we see that the identifier this.fruit inside our two nested single execution functions resolved to the global fruit variable. In the case of the single execution function inside the say function, the value of this.fruit was still 'banana' even though the say function itself has its this keyword pointing to the object object. This means that the outer function doesn't affect the this value of the inner nested function.

Earlier I said that the this value is mutable and this ability to change the value of the keyword has several uses in JavaScript. Functions have two methods that can be used to change the this value: apply and call. These methods are actually used to invoke the function without the invocation operator (i.e., without the use of ( ) after the function identifier), but you can also provide arguments to these methods to change the behavior of the function.

The apply method takes two arguments: thisValue, which is used as the value of this inside the function, and params, which is an array of arguments to pass to the function. When the apply method is called on a function without any arguments or when the first argument passed is null, the this value of the function becomes the global object and no arguments are passed:

var fruit = 'banana';

var object = {

    fruit: 'orange',

    say: function(){
        console.log(this.fruit);
    }

};

object.say(); // 'orange'
object.say.apply(); // 'banana'

Reusing a snippet from the last example, we see that when we used apply without arguments to the object.say function, the this value of the function becomes the global object rather than the object itself—thereby resolving this.fruit to be 'banana' rather than 'orange'.

To set the this value of a function to another object, you simply have to pass a reference to the object using the apply function:

function add(){
    console.log(this.a + this.b);
};

var a = 12;
var b = 13;

add(); // 25

var values = {a: 50, b: 23};

add.apply(values); // 73

The apply method's second argument can be used to pass arguments to the function being called. This argument should be in the form of an array containing values that correspond to the function's formal parameters:

function add(a, b){
    console.log(a); // 20
    console.log(b); // 50
    console.log(a + b); // 70
};

add.apply(null, [20, 50]);

The other function method, call, works the same way as apply and thus follows the same rules indicated above. The only difference is that call can take multiple arguments after the thisValue argument, and these arguments will correspond to the formal parameters of the function in the order they were declared:

function add(a, b){
    console.log(a); // 20
    console.log(b); // 50
    console.log(a + b); // 70
};

add.call(null, 20, 50);

Advanced Function Techniques

The previous sections are meant as a base from which to start our explorations of functions. However, in order to fully utilize the power of JavaScript functions, we must be able to apply the various bits and pieces we've learned from those sections.

In the next sections, we'll discuss some of the advanced function techniques we can use in our code and we'll explore various uses for the things we've learned so far. Like everything else in this book, the information here is not meant to be exhaustive, but rather a starting point for further experimentation.

Limiting Scope

Let's say we have a program that needs to keep track of the user's name and age. We have a variable, user, which is an object where we keep the necessary data and two sets of functions, setName and getName, setAge and getAge, that we'll use to set and get the data:

// the `user` object where we keep the data
var user = {name: 'Mark', age: 23};

function setName(name){
    // make sure the name is a string
if (typeof name == 'string') user.name = name;
};

function getName(){
    return user.name;
};

function setAge(age){
    // make sure the age is a number
    if (typeof age == 'number') user.age = age;
};

function getAge(){
    return user.age;
};

// set a new name
setName('Joseph'),
console.log(getName()); // 'Joseph'

// set a new age
setAge(22);
console.log(getAge()); // 22

So far, so good. Our setName and setAge functions have checks to ensure that our values are of the correct type before setting them. However, we notice that the user variable is in the global scope and it's accessible everywhere. This presents a problem since you could just set the names without using the functions we've declared:

user.name = 22;
user.age = 'Joseph';

console.log(getName()); // 22
console.log(getAge()); // 'Joseph'

This isn't good, since we want the values to be correctly typed.

So what can we do? If you recall, variables declared inside a function are local to the function itself and are not accessible outside, and closures provide a way for a function to retain references to the local variables of its surrounding function. We can combine both of these points to limit our user variable to a local scope and then use closures for our setter and getter functions:

// create a single execution function
// to encapsulate the code and localize the user variable
(function(){

    // our variable is now local
    var user = {name: 'Mark', age: 23};

    // make our functions global
    setName = function(name){
        if (typeof name == 'string') user.name = name;
    };

    getName = function(){
        return user.name;
    };

    setAge = function(age){
        if (typeof age == 'number') user.age = age;
    };

    getAge = function(){
        return user.age;
    };

})();

// set a new name
setName('Joseph'),
console.log(getName()); // 'Joseph'

// set a new age
setAge(22);
console.log(getAge()); // 22

Now, if someone tries to set the values of user.name or user.age without going through the functions, it will result in a runtime error since the user object is no longer available to any other code except our getter and setter functions.

Currying

One of the best things about having first-class functions is the ability to create these functions during runtime and store them in variables. Say we have the following snippet:

function add(a, b){
    return a + b;
};

add(5, 2);
add(5, 5);
add(5, 200);

Our last three lines call the function add to add 5 and another number. We're adding the same base number (5) to different numbers multiple times and it seems better if we could just set the function to add 5 instead of having to type it every time. We could modify our add function to use 5 + b instead, but other parts of our program might already use the add function, so this won't do. Wouldn't it be nice if we could dynamically modify our add function without changing it entirely?

It turns out we can. This technique is called partial application or currying, and it involves creating a function that "applies" some of the arguments ahead of time:

function add(a, b){
    return a + b;
};
function add5(b){
    return add(5, b);
};

add5(2);
add5(5);
add5(200);

Here, we create an add5 function that calls our add function with a preset value (in this case, 5). The add5 function is essentially our add function but with an argument already applied (hence, partial application). However, the snippet above doesn't show the dynamic part. What if we have other parts in our code where we can use this? If we were to do as we did above, we'd have to create a new function for each of the partially applied functions we want.

This is where first-class functions come in handy. Instead of explicitly declaring our new add5 function, we can have another function that takes a function as its argument and then returns a modified copy of that function. In our case, we can create a function that modifies our add function dynamically to create a new partially applied function:

function add(a, b){
    return a + b;
};

function curryAdd(a){
    return function(b){
        return add(a, b);
    };
};

var add5 = curryAdd(5);

add5(2);
add5(5);
add5(200);

In this snippet we introduce a new function called curryAdd. It takes a single argument, a, which will be the value passed as the a argument to the original add function. It then returns a new function that has one formal parameter, b, which will be used as the b argument to add. When we call this new function via curryAdd(5), it returns a new partially applied function that we store in a variable. Because we have a closure, the partially applied function retains a reference to the a variable from our curryAdd function, making it usable for the next invocations.

This, of course, is a very trivial application of curried functions, but it suffices to show how the technique works. You'll find uses for currying in many parts of your code and it's a technique that comes in handy during day-to-day development.

Decoration

Another technique that uses dynamic modification of functions and closures is decoration. The operative word is "decorate," and function decoration involves taking a function and adding new "features" to it dynamically.

Say we have a function that takes a single object as its argument and stores the key-value pairs in another object:

(function(){

    var storage = {};

    store = function(obj){
        for (var i in obj) storage[i] = obj[i];
    };

    retrieve = function(key){
        return storage[key];
    };

})();

console.log(retrieve('name')); // undefined

store({name: 'Mark', age: 23});
console.log(retrieve('name')); // 'Mark'

What if we want our store function to take in a pair of arguments instead of just a single object? So instead of doing store({name: 'Mark'}), we also want to be able to do store('name', 'Mark'). We could modify our store function to do this, but we've also used a similar style in other parts of our code, so it's better if we can do this dynamically.

What we can do is to create a decorator function that will wrap our store function:

var decoratePair = function(fn){
    return function(key, value){
        if (typeof key == 'string'){
            var _temp = {};
            _temp[key] = value;
            key = _temp;
        }
        return fn(key);
    };
};

(function(){

    var storage = {};

    store = decoratePair(function(obj){
        for (var i in obj) storage[i] = obj[i];
    });

    retrieve = function(key){
        return storage[key];
    };

})();

console.log(retrieve('name')); // undefined

store('name', 'Mark'),
console.log(retrieve('name')); // 'Mark'

This is one of the more complex examples we've seen so far, so let's take it step by step. First, we declared a new function called decoratePair that takes a single argument, fn, which is the function we're decorating. decoratePair then returns a new decorated function that takes two arguments, key and value. Since our original store function takes only a single object as its argument, the decorated function checks whether the first argument is an object or a string. If it's not a string, the wrapped function will immediately be called. However, if it's a string, the function turns it into an object before it calls the wrapped function. When we define the store function, we pass the original function to decoratePair as a literal.

Our decorator above ensures that we have proper arguments for the wrapped function before calling it, but decorators can also add features after the function is called. Here we have a simple decorator that takes the arguments from our add function and multiplies them by the second argument:

var add = function(a, b){
    return a + b;
};

var decorateMultiply = function(fn){
    return function(a, b){
        var result = fn(a, b);
        return result * b;
    };
};

var addThenMultiply = decorateMultiply(add);

console.log(add(2, 3)); // 5
console.log(addThenMultiply(2, 3)); // 15

Here we created the function addThenMultiply dynamically by passing the original add function to decorateMultiply. The result is a function that saves the results of the add function and modifies it before returning the value.

Function decoration is useful for a lot of tasks and it enables you to extend functions without having to modify them directly. This is especially handy for built-in functions that you can't modify directly, as well as third-party code you can't control.

Combination

A similar technique to decoration is combination, which involves putting together two functions to create a new function. Unlike decoration, combination involves directly passing the results of one function to another.

Here's a simple example of how it works:

var add = function(a, b){
    return a + b;
};

var square = function(a){
    return a * a;
};

var result = square(add(3, 5));
console.log(result); // 64

The square(add(3, 5)) code shows how combination works, but it's not exactly a combined function. Here, the value returned from add(3, 5), which is 8, is passed to the square function, which in turn returns 64. To make this a combined function, we have to automate the process so that we don't have to type square(add(a, b)) all the time.

While we could simply create a function that has the square(add(a, b)) code inside it, the better way is to write a combinator function that takes two functions and combines them:

var add = function(a, b){
    return a + b;
};

var square = function(a){
    return a * a;
};

var combine = function(fnA, fnB){
    return function(){
        var args = Array.prototype.slice.call(arguments);
        var result = fnA.apply(null, args);
        return fnB.call(null, results);
    };
};

var addThenSquare = combine(add, square);

var result = addThenSquare(3, 5);
console.log(result); // 64

Our new combinator in this snippet, called combine, is a function that takes two arguments, fnA and fnB, which correspond to the two functions to be combined. It then returns a new combined function. The innards of the combined function are more complex than what we've seen in past examples, but it essentially takes the arguments passed to the function, turns them into an array, uses the apply method of functions to invoke the first function, fnA, and then stores the result in a variable. The result is then passed to the second function, fnB, before it's returned. We then create a new function, addThenSquare, by passing the references to our add and square functions to our combinator. The result is a function that combines our two small functions together.

Note that the order is important when combining functions, as well the number of arguments. In our example, we can't have a squareThenAdd function, since square takes only one argument and returns one value while add needs two arguments. And since JavaScript only allows for one return value, combined functions are usually limited to functions that take a single argument.

MooTools and Functions

You'll notice that, so far, much of our discussion has centered on functions in the context of JavaScript, and MooTools is strangely out of the picture. This is not so unusual if you remember that MooTools doesn't try to turn JavaScript into something else but rather uses the available features of the language to make it more powerful. The information we've learned so far is core to how MooTools implements new features, and a cursory glance at the MooTools source code will show its extensive use of features like single execution functions for limiting scope, closures, currying, and decoration and other techniques.

In the next sections, we'll take a look at some of the features that MooTools adds to functions, and see how they can be used for our own applications.

Function Binding

If you recall from a previous section, we learned that a function's this value is mutable and that we can change it using the apply and call methods. However, there are cases when it's time-consuming if we have to use apply and call each time:

function setName(name){
    this.name = name;
};

var object = {name: 'Mark'};

setName.call(object, 'Joseph'),
setName.call(object, 'Olie'),
setName.call(object, 'Patrick'),

A better solution would be to create a new version of the setName function that would be automatically bound to the object:

function setName(name){
    this.name = name;
};

var object = {name: 'Mark'};

function setObjectName(name){
    setName.call(object, name);
};

setObjectName('Joseph'),
setObjectName('Olie'),
setObjectName('Patrick'),

This technique is called binding, and it's much better than the earlier example since it eliminates the need to use call all the time. But it's a bit time-consuming to declare new functions for all functions you want to rebind. Fortunately, MooTools gives us an easier way to do this using the bind method of functions. Our code above can be simplified using this method:

function setName(name){
    this.name = name;
};

var object = {name: 'Mark'};

var setObjectName = setName.bind(object);

setObjectName('Joseph'),
setObjectName('Olie'),
setObjectName('Patrick'),

The first argument to the bind method is an object that will be the this value of the new function. The method then returns a new function similar to the example we had in the previous snippet.

All arguments passed to bind after the first argument are passed as arguments to the function being bound. If we have several calls to setName.call(object, 'Mark') in our code, we could simply create a new function using var setObjectToMark = setName.bind(object, ['Mark']), and replace our previous calls with setObjectToMark(). Note, however, that bind does not do partial application: if we leave out any arguments to the function, they will be set to undefined.

Extending Functions with Methods

While MooTools already includes several useful function methods, it also allows developers to add new function methods easily. We'll discuss much of how this native extension mechanism works in Chapter 6, but right now we'll focus on how we can use this MooTools feature to add new methods.

The MooTools way to add new function methods is via Function.implement. Here's an example:

// create a new function method `thenAdd`
Function.implement('thenAdd', function(num){
    var self = this;
    return function(){
        var args = Array.prototype.slice.call(arguments);
        var result = self.apply(null, args);
        return result + num;
    };
});

var add = function(a, b){
    return a + b;
};

// modify the add function to add 5 to the result
var addThenAdd5 = add.thenAdd(5);

console.log(addThenAdd5(2, 3)); // 10

var square = function(a){
    return a * a;
};

// modify the square function to add 2 to the result
var squareThenAdd2 = square.thenAdd(2);

console.log(squareThenAdd2(5)); // 27

To create the new method, we called Function.implement with two arguments: a string with the value 'thenAdd', which will be the name of the method, and a function, which will be the actual method. Our actual thenAdd method is a function that takes one argument, num, which is the number to add to the result of the function we're modifying. It then returns a new function that wraps the original function.

You'll notice that we didn't have to specify the function itself that we were modifying in our thenAdd method. Since it's a function method, the this keyword inside our method body already points to the function, so when we called add.thenAdd(5), this referred to the add function, and the same thing happens for the square.thenAdd(2) call. One other thing we did was to save the reference to the function to a local variable via the line var self = this; so that we can reference the function inside the new function we're creating. If we didn't do this, we'd lose reference to the function since the value of this inside the new function would be the global object instead of the function we're modifying.

As in previous examples, you'll see that a closure is created, enabling us to reference both the original function via self and the number argument to the thenAdd method. We also used the Array.prototype.slice.call(arguments) technique to turn our arguments object into an array so that we can use it with the apply method, and this also gives our new function flexibility to handle a variable number of arguments. The result is a new function method that adds a number to the result of the original function.

In the previous section on combination, we used a combinator function to join two functions. We could rewrite our old combinator function into a new function method to make it easier to reuse the function:

Function.implement('combine', function(fn){
    var self = this;
    return function(){
        var args = Array.prototype.slice.call(arguments);
        var result = self.apply(null, args);
        return fn(result);
    };
});

var add = function(a, b){
    return a + b;
};

var square = function(a){
    return a * a;
};

var addThenSquare = add.combine(square);

var result = addThenSquare(3, 5);
console.log(result); // 64

If you're creating more than one method, you can pass Function.implement a single object argument instead of a string and a function. If we were to add our two methods above in one go, we could do this by passing an object instead:

Function.implement({

    addThen: function(num){
        var self = this;
        return function(){
            var args = Array.prototype.slice.call(arguments);
            var result = self.apply(null, args);
            return result + num;
        };
    },

    combine: function(fn){
        var self = this;
        return function(){
            var args = Array.prototype.slice.call(arguments);
            var result = self.apply(null, args);
            return fn(result);
        };
    }

});

The Wrap Up

As we've seen in this chapter, JavaScript's implementation of functions is truly amazing. JavaScript functions are powerful and complex—both from the developer's and the interpreter's points of view. We saw the different forms of functions available to us and discussed seemingly simple elements such as arguments and return values. We also dived deep into the internals of functions and learned about execution contexts, variable instantiation, and scoping. Finally, we discussed the various advanced techniques and features of JavaScript functions like closures, currying, decoration, and dynamic modification, and we toured the additional features that MooTools provides.

I hope you've learned a lot about how powerful and complex JavaScript functions are and that you picked up a few nifty techniques to use in your own programs. However, we're just getting started in our exploration and this chapter is meant to be the starting point for more complex JavaScript topics.

In the next chapter, we'll learn about objects and dive headfirst into JavaScript's own flavor of object-oriented programming. So if you're ready, turn to the next chapter and let's get started.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset