In-depth guide to javascript functions

Christian Harms's picture

You already know how to define or assign functions directly, use multi parameter arguments in anonymous calls and know all the different variants of the function-constructor? Then you won't find anything new about the subtle differences in using functions in JavaScript.

The work title of this article was "Different ways to define JavaScript functions". Some code examples look quite similar but the differences can be important. While I am explaining the different ways to define JavaScript functions, you can test the code directly: install the firebug plugin and use the JavaScript console to play interactively below the article.

Function Statement

In the first example here I define a function to wrap the "window.alert"-function to open the default javascript popup-Message box:

  1. function hello(msg) {
  2.   alert(msg);
  3. }

It defines a function object in the relative namespace, named hello with one parameter msg. If you define it directly in a script-part of an html-document the function name is available in the global namespace of the document.

  1. function fib(n) {
  2.   return (n<2)?n:fib(n-1)+fib(n-2);
  3. }

Here you can see a example with recursion - the classic Fibonacci function. While using the function statement you can use the function name in the function directly because the function name is defined before the function is interpreted. Dont try start the function with more than 50 - its very expensive.

  1. function two(n) {
  2.   return one(n) * 2;
  3. }
  4.  
  5. document.write(two(4));
  6.  
  7. function one(n) {
  8.   return n;
  9. }

A special case is to call a function before (JavaScript is based on an interpreter, not a compiler) it's defined: function two calls function one. The JavaScript parser works bottom up but all names of functions statements are known at start. The example can not used with function literals - it will produce an "one is not defined"-Error.

Function constructor

Functions in JavaScript can be used as variables and passed as arguments to other functions: they are objects like String or Object. They can also be created by using the Function constructor.

  1.  var product = new Function("a", "b", "return x*y;");

The last string argument is the function body with the JavaScript code, all arguments before it define the argument names. This variant can be used to generate new function with generated JavaScript code.

But the function body has to be parsed on every run, so performance is rather bad and the function is almost impossible to be precompiled. But be careful:

  1. var msg = "global";
  2. function test() {
  3.   var msg = "local";
  4.   var intern = new Function("return msg;");
  5.   return intern();
  6. }
  7. test(); // -> "global"

The local function intern runs in global scope and returns "global" instead of "local" like expected!

Function literals

  1. var hello = function(msg) {
  2.   alert(msg);
  3. }

The difference to the first function statement example is that the anonymous function can be assigned directly to the variable hello (typeof(hello)=="function"). With a function literal you can assign function into a defined namespace instead the relative scope like the function statement. The problem namespacing in JavaScript is an other interesting thing you can find by fotiweb.com or phpied.com more. In JavaScript you use simple objects with the default syntax "{}" to define namespace holder. This is the first step to write clean JavaScript without having namespace problems if an other JavaScript lib defines the same global variable (There exists more than one popular lib with defining the variable "$" global).

  1. var com = com||{};
  2. com.unitedCoders = com.unitedCoders||{};
  3. com.unitedCoders.hello = function(msg) { alert(msg); };
  4.  
  5. //Using this function with name-space:
  6. com.unitedCoders.hello("Calling with name-space!");

But back to the function literal and how we can write the example "fib" - the above example show that this wont work.

  1. var fib = function(n) { return (n<2)?n:fib(n-1) + fib(n-2); }
  2. var fib2 = fib;
  3. fib = undefined;

You can assign a function value to another variable or overwrite variables (for example with undefined). In the example the first line will be correct, but after deleting fib the inner part in the function fib2 will produce a "TypeError: fib is not a function". The first, but rarely seen solution is the usage of the local function name.

  1. var fib = function myfib(n) { return (n<2)?n:myfib(n-1) + myfib(n-2); }

The function name myfib is only available in the function - say the local scope. You can assign the variable fib to any other name the local name myfib will always available. If you assign the function to a variable myfib the local scope will exist.

The other solution is using the callee - object who is available with the special identifier arguments (a list of all arguments) when calling the function. There is also no need to define the parameter names in the function header.

  1. var sum = function() {
  2.   var sum = 0;
  3.   for (var i=0; i<arguments.length; i++) {
  4.     sum += arguments[i];
  5.   }
  6.   return sum;
  7. };

The identifier arguments offer the callee-property and it's a reference to the local function itself. With this reference there is the clean solution for recursion without a local function name:
  1. var fib = function(n) {
  2.   return (n<2)?n:arguments.callee(n-1)+arguments.callee(n-2);
  3. };

See on the next page what anonymous functions are and more examples for eval.

in-depth guide to javascript functions

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Comments

Anonymous's picture

Please display complex function for those who wants to expertise in javascript..............

Christian Harms's picture

What are "more complex function"? You want a class design or more mathematical functions? I will plan in both directions.

Combining HTTP and JavaScript APIs with php | united-coders.'s picture

[...] The function wrapper chooses all positions with a set city, hoping these lat/long value pairs are the most accurate [...]

Tutorial for a IP to geolocation aggregator script | united-'s picture

[...] javascript interface is ugly and the data defing global functions, which can't be removed from the global [...]

Forfeit game - coding contest since 50 years | united-coders's picture

[...] Matthia's has delivered a clean code variant for the problem and it will be used as the reference for this coding contest. It's not the fastest solution but offers a direct implementation of the problem. Matthias uses an extra function for every condition and put it together in the main loop. function cleanCodeSolution(n){         for (var i=0, res=[]; i <= n; i++) {             if (!(containsSeven(i) || isMultipleOfSeven(i) ||                   sumContainsSeven(i) || sumIsMultipleOfSeven(i))) {                 res.push(i);             }         }         return res;         //all helper functions defined in local scope         function containsSeven (n) {             return String(n).indexOf("7") !== -1;         };         function isMultipleOfSeven (n) {             return n % 7 === 0;         };         function sumContainsSeven (n) {             return containsSeven(sumOfDigits(n));         };         function sumIsMultipleOfSeven (n) {             return isMultipleOfSeven(sumOfDigits(n));         } ;         function sumOfDigits (n) {             var sum = 0;             while (n > 0) {                 sum += n % 10;                 n = Math.floor(n / 10);             }             return sum;         }; } If you are surprised about using the helper function before defining, read more about function defining the the In-depth guide to javascript functions. [...]