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, as follows:

    var f = function () { 
      return 1; 
    }; 

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

The function () { return 1;} part 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" as shown in the following example:

    > 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 the following 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, as follows:

    > var sum = function (a, b) { 
        return a + b; 
      }; 
 
    > var add = sum; 
    > typeof add; 
    function 
    > add(1, 2); 
    3 

As 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 the following:

    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, which are as follows:

  • 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

As 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 returns hardcoded values:

    function one() { 
      return 1; 
    } 
   
    function two() { 
      return 2; 
    } 

Now you can pass those functions to the original function, invokeAdd(), and get the following 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 by deferring the execution or by unblocking calls

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, as follows:

    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; 
    } 

Using the modified function, all the work is done with just one function call, which passes the start values and the callback function, as follows:

    > 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, for example:

    ( 
      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 piece of code 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, here's the example:

    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 follows:

    var outer = function (param) { 
      var inner = function (theinput) { 
        return theinput * 2; 
      }; 
      return 'The result is ' + inner(param); 
    }; 

When you call the global outer()function, it will internally call the local inner()function. As 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 can keep the global namespace clean, which is less likely to cause naming collisions
  • Privacy-you can expose only those functions to the outside world that you decide, and keep the functionality that is not meant to be consumed by the rest of the application to yourself

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, for example:

    function a() { 
      alert('A!'), 
      return function () { 
        alert('B!'), 
      }; 
    } 

In this example, the a()function 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, as follows:

    > 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!

As 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 preceding line of code 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 and the returned value was assigned back to the function. But, the function can actually rewrite itself from the inside, as shown in the following example:

    function a() { 
      alert('A!'), 
      a = function () { 
        alert('B!'), 
      }; 
    } 

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

  • Alert A! (consider this as being the one-off preparatory work)
  • Redefine the global variable a and 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; 
 
    }()); 

From this example, you can note the following things:

  • 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 actualWork variable, 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.
  • As 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 be in the following cases:

  • 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.

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

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