Dofactory.com
Dofactory.com
Earn income with your JavaScript skills
Sign up and we'll send you the best freelance opportunities straight to your inbox.
We're building the largest freelancing marketplace for people like you.
By adding your name & email you agree to our terms, privacy and cookie policies.

JavaScript Functions

A JavaScript Function is a block of JavaScript code that performs a task or calculates a value. A function has a name and it usually takes in some input and returns an output. Functions are reusable and can be executed as many times as necessary.

JavaScript Tutorial

Declaring Functions

Functions, as reusable blocks of code, are fully supported in JavaScript. Here is an example of a simple function declaration:

function say(name) {
    console.log("Hello " + name);
}

say("Nico");           // => Hello Nico

The above function declaration starts with the keyword function. Next we have say, which is the function's name. Following the name is a comma-separated list of zero or more parameters enclosed by parentheses: (). In our example we have one parameter named name. These parameters behave like local variables inside the function body. The function body comprises a set of JavaScript statements enclosed by curly braces: {}. The body executes when the function is invoked by issueing its name followed by parenthesis (with possible arguments), like say("Nico");.

Function declarations can appear in the top-level JavaScript program itself, just like our say example. However, functions can also be nested within other functions, like so.

function hypotenuse(m, n) {        // outer function  
    function square(num) {         // inner function
        return num * num;
    }
    return Math.sqrt(square(m) + square(n));
}

console.log(hypotenuse(3, 4));     // => 5

The outer function hypotenuse contains an inner function square. The square function is visible only within the hypotenuse function body, that is, square has function scope only. The easiest way to look at square is as a private helper function to the outer function.


Function Expressions

The examples before are function declarations. However, JavaScript also supports function expressions in which functions are assigned to variables. Here is an example:

var area = function (radius) {
    return Math.PI * radius * radius;
};

console.log(area(5));         // => 78.5398..

This function is assigned to a variable named area. The function itself does not have a name, so this is an anonymous function. Function expressions are invoked by calling the variable name with a pair of parentheses containing any arguments (in our example: area(5));.

How do we distinguish a function declaration from a function expression? A ny time a function is a part of an assignment, it is treated as a function expression. Function declarations do not end with a semicolon, whereas function expressions do, as they are part of an assignment. Also, function declarations must always have a name whereas a function expression may or may not have a name, i.e. it can be named or anonymous.

Anonymous functions are commonly used in JavaScript. Our area function is an example of this. By the way: if you choose to give the function expression a name it is generally recommended you give it the same name as the variable it is assigned to; this will avoid confusion.

Function Hoisting

A JavaScript function can be invoked before its declaration. This works because the JavaScript engine implicitly hoists the function to the top so that they are visible throughout the program. In the example below, the function named course is parsed and evaluated before any other code is run.

function course() {        // hoisted to top of program    
    return "Learning JS";
}

console.log(course());     // => Learning JS

Variable Scope in Functions

A variable has global scope if it exists during the life of the program and is accessible from anywhere in the program. A variable has function scope if it is declared within a function and is not accessible outside of that function and will cease to exist when the function finishes execution.

With function scope, the parameters and variables that you define as part of a function are not available outside the function body; they are only visible within the function throughout the lifetime of the function. Here are some examples:

var num = 1;           // variable is global
function showGlobal() {
    console.log(num);  // uses the global num
}

showGlobal();          // => 1

function showLocal() {
    var num = 2;       // num is local, hides the global num 
    console.log(num);
}

showLocal();           // => 2

function showArgument(num) {
    console.log(num);  // arguments are locally scoped
}

showArgument(3);       // => 3

Unfortunately JavaScript does not support block-level scoping. A variable defined within a block, for instance an if- or a for-statement, will exist even after the block finishes execution. It will be available until the function in which the variable is declared finishes.

function noBlock() {
    if (true) {
        var width = 10;  // not block level scoped
    }
    console.log(width);  // variable num is available outside the if block
}

noBlock();               // => 10

JavaScript functions can be nested within other functions. A nested (inner) function can access the arguments and variables of the (outer) function it is nested within. The example below demonstrates this:

function verify(name) {             // outer function  
    function isJohn() {             // inner function
        return name === "John";     // full access to argument        
    }
    if (isJohn()) {
        console.log("Yep, this is John");
    }
}

verify("John");

The inner function isJohn has full access to the name argument of the outer function; there is no need to pass a parameter to the inner function.


Variable Scoping and Prototypes

What happens when a function has a property and its prototype has a property of the same name? Which one will be used? Let's run a test and find out:

function Counter(count) {
    this.count = count;           // object property
}

Counter.prototype.count = 2;      // prototype property

var counter = new Counter(6);
console.log(counter.count);       // => 6

This code demonstrates object properties take precedence over (i.e. hide) prototype properties of the same name.


Closures

Closures are an important and powerful concept in JavaScript. Simply put, a closure represents the variables of a function that are kept alive, even after the function returns. In almost all other languages when a function returns all local variables are destroyed and the program moves on, but not in JavaScript.

Many JavaScript programmers are familiar with the concept of holding a reference to a function with a variable (if not, see the discussion of function expressions before this section). Many other languages have similar concepts where they can reference functions through function pointers or delegates. However, in JavaScript when a variable holds a reference to a function it also maintains a second, but hidden, reference to its closure, which essentially are the local variables that were present at the time of creation and their current values. These variables are its scope context. Let's show this with an example (note that counter() is a regular function and not a constructor function):

function counter() {
    var index = 0;
    function increment() {
        index = index + 1;
        console.log(index);
        return index;
    }
    return increment;
}

var userIncrement = counter();    // a reference to inner increment()
var adminIncrement = counter();   // a reference to inner increment()

userIncrement();                  // => 1
userIncrement();                  // => 2
adminIncrement();                 // => 1
adminIncrement();                 // => 2
adminIncrement();                 // => 3

When the counter function is invoked, it returns a reference to the increment function. At the time counter finishes execution, JavaScript saves its scope, and only the function that it returns, in our example increment, has access to it. This is the function's closure and includes a copy of the variable index, which is 0 following the initialization. Subsequent calls to increment increments the index value. Note that userIncrement and adminIncrement each have their own closure with their own copy of the index variable that only they can work on.

Arguments are local to their functions, so they also become part of the closure context. Here is an example in which name is part of the closure.

function greetings(name) {
    function sayWelcome() {
        console.log("Welcome to " + name);
    }
    return sayWelcome;
}

var greet = greetings("New York");

greet();           // => Welcome to New York
greet();           // => Welcome to New York
greet();           // => Welcome to New York

Since all JavaScript functions are objects and they have a scope chain associated with them, they are, in fact, closures. Most commonly however, a closure is created when a nested function object is returned from the function within which it was defined.

The nested function closures are a powerful feature of JavaScript and they are commonly used in advanced applications. For instance, it is commonly used when declaring event callbacks. Many JavaScript libraries make use of closures. Our unique Dofactory JS demonstrates many advanced uses of JavaScript closures. To learn more click here.


Option Hash Pattern

Suppose you have a function that expects a large number of parameters, like this:

function createCompany(name, street, city, zip, state, type,  
                       taxId, currency, isActive, parentCompany) { 
    ...
}    

It would be difficult for the client of the function to recall all the parameters and put them in the correct order. When you invoke a function in JavaScript with an incorrect number or order of arguments you are not going to get an error. It just makes the missing variables undefined. So, it is easy to introduce bugs when calling functions that accepts a large number of parameters.

An nice solution to this kind of scenario is called the Options Hash pattern. Essentially, it is a function that accepts a single parameter which is an object that encapsulates all the parameters:

var parms = {
    name: "Levis",
    street: "1 Main Street",
    city: "Anyhwere",
    zip: "01010",
    state: "NY",
    type: "Garments",
    taxid: "983233-003",
    currency: "USD",
    isActive: true
};

function createCompany(parms) {
    var name = parms.name;
    var street = parms.street;
    var city = parms.city;
    console.log("State: " + parms.state);
    console.log("Currency: " + parms.currency);
    // ...
}

createCompany(parms);

The variable parms is a simple object literal. It allows the parameters to be added in any order. Also, optional parameters, such as parentCompany in the earlier code with the long parameter list, can be safely omitted. It is far easier to maintain a parameter object than a list of individual parameters and worry about passing them in correctly. By the way, this pattern also allows you to pass in more complex types, such as callback functions.

Our Dofactory JS has more to say about the Option Hash pattern, including a wonderfully elegant way to handle default and missing values. To learn more click here.


Immediate functions

Immediate functions execute as soon as JavaScript encounters them. These functions are a powerful concept that is frequently used in JavaScript. They are also referred to as self-invoking functions. First let's look at a normal function declaration. Clearly, it does not execute until it's invoked.

function print() {
    console.log('Learning JS!');
}

print();          // executes print function

JavaScript allows you to execute a function immediately by enclosing it with parentheses followed by another pair of parentheses, like so:

(function () {
    console.log("Learning JS!");
}());

The opening parenthesis before a function keyword tells the JavaScript to interpret the function keyword as a function expression. Without it, the interpreter treats it as a function declaration. The paired brackets () at the end is the argument list; in this case an empty list.

The example above is an anonymous function, that is, it has no name. There is no need for a name, because nowhere in the program will this function be called. It is called once, as soon as JavaScript encounters it.

You can also pass parameters to an immediate function.

(function square(value) {
    var result = value * value;
    console.log(result);
})(10);

Any variable you define in an immediate function, including the arguments passed, remains local to the function. By using these self-invoking functions, your global namespace won't be polluted with temporary variables.

Immediate functions offer great flexibility and are widely used in the most popular JavaScript frameworks, such as jQuery. Our accompanying Dofactory JS includes a great section on immediate functions and how JavaScript experts are using them to build robust and maintainable web apps. To learn more click here.

Next, we will look at an area where immediate functions can be useful: page initialization.


Web Page Initialization

Immediate functions are useful for initialization tasks that are needed only once. A good example is when a web page is loaded in which you initialize objects, assign event handlers, etc. Using an immediate function allows you to package and run this process in the local scope of the function without leaving a global trace behind; only local variables are created and no global variables are left behind. The example below simply displays a welcome message with today's day.

(function () {
    var days = ["Sunday", "Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday"];

    var today = new Date();

    var message = "Welcome, today is " + days[today.getDay()];

    console.log(message);     // => Welcome, today is Monday
}());

This function executes once and there will be no trace left. If the above code were not wrapped in an immediate function, the variables days, today, and message would all end up on the global namespace, increasing the risk of name collisions. With the immediate function we have zero footprint on the global namespace.


call(), apply()

Functions in JavaScript have several built-in methods, two of which we will examine here; call() and apply(). This may sound strange, but remember that a function in JavaScript is an object so it has its own properties and its own methods. The methods call() and apply() allow you to invoke the function, giving you a lot of control over how the function executes. Consider the following code:

function message() {
    console.log(this.num);
}

message();        // => undefined, 'this' references global object

var obj = { num: 2 };

message.call(obj);        // => 2,  'this' references obj
message.apply(obj);       // => 2,  'this' references obj

The functions call and apply are very similar: the first argument passed is the same, which is the object on which the function is to be invoked. With this argument you essentially control what this is bound to inside the function body. This is a powerful concept, because what this implies is that any function can be invoked as a method of any object, even when it is not actually a method of that object. If you are familiar with .NET extension methods, then you'll immediately understand the concept.

An optional second argument to call() is a number of arguments to be passed to the function that is invoked. In apply() the optional second argument is the same, but specified as an array of arbitrary length. When you know the exact number of arguments use call(), otherwise use apply().

Here is another example of both methods in action.

var welcome = function (guest) {
    console.log("I'm " + this.name + ", you're " + guest.name);
};

var stan = { name: "Stan" };
var laurel = { name: "Laurel" };

welcome.call(stan, laurel);    // => I'm Stan, you're Laurel
welcome.call(laurel, stan);    // => I'm Laurel, you're Stan

welcome.apply(stan, [laurel]); // => I'm Stan, you're Laurel
welcome.apply(laurel, [stan]); // => I'm Laurel, you're Stan

The first call has stan bound to this and laurel as the guest. In the second call the roles are reversed. The apply methods are the same except that the guest argument is passed as an array.

For a broader discussion on these powerful functions and additional invocation patterns check out our unique Dofactory JS product. To learn more click here.


Last updated on Sep 30, 2023

Earn income with your JavaScript skills
Sign up and we'll send you the best freelance opportunities straight to your inbox.
We're building the largest freelancing marketplace for people like you.
By adding your name & email you agree to our terms, privacy and cookie policies.
Guides