The power of JavaScript Functions

WeeklyWebWisdom
1,944 views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

“Functions are the very best part of JavaScript. It’s where most of the power and the beauty of this language is.” Douglas Crockford

Functions can be seen as the JavaScript’s workhorses. They alone play roles that other languages fulfill with multiple distinct features: procedures, methods, constructors and even classes and modules. Every one of this is covered by the versatility of functions.

In the newest version of Javascript, concepts like class, method and constructor were introduced but this are nothing more than syntactic sugar over the same functionalities, already covered by the function.

Once you become comfortable with the finer points of functions, you have mastered a significant portion of Javascript. Of course, the flip side of the coin is that it can take some time to learn how to use functions effectively in different context.

This article aims to provide a walkthrough the concept of functions in JS from the very basics to the less known subtleties.

Functions as objects

An important particularity of Javascript is the fact that functions are a special type of object. Declaring a function is similar to an object literal because it’s producing an object function.

This object function is a first classed object: it can be passed as argument, return from a function, assigned to a variable, store to an object or array – anything you can do with an object, you can do with a function -. It’s inheriting from Function.prototype which gives it access to methods like bind(), apply() and call().

Looking at a function like an object may be a big paradigm shift for many developers with experience on other languages, but understanding this will give much more sense to what we are going to talk about later.

Function structure

There are two ways of declaring a function:

// function expression 
var sum = function(a, b) { 
     return a + b; 
}

// function statement
function sum(a, b) {
    return a + b;
}

The keyword function precedes the declaration. The name is optional for function expression but mandatory for function declaration.

Another aspect worth noticing is that in JS the concept of ‘function signature’ doesn’t exist. You can call any function with as many or as few arguments as you wish without encountering any errors. If the arguments are not provided with a value, they will be undefined. Luckily, there is a way of knowing exactly how many arguments were provided using the arguments object.

Functions does not required an explicit return but it’s important to know that, when no explicit return is made, the function will return undefined . The only exception to this rule is the function used as a constructor, which returns the new object

Remember:

  • ‘function signature’ doesn’t exist – any function can be called with any number of arguments
  • function always return a value – if not explicitly provided, it’s undefined (except constructor which >return the new object)
  • as best practice, it’s recommended to either always return a value in a function or never return anything

Variable scope

A variable scope determines the accessibility (visibility) of a variable. In Javascript, there are 2 types of scopes – global and local (inside a function) -.

Whenever a function is called, a new scope is created. Local variables have local scope: They can only be accessed within the function.

When a variable is declared using var, is automatically added to the most immediate scope available. In a function, the most immediate one would be to function’s local context. Since local variables are only recognized inside their functions, variables with the same name can be used in different functions.

Each function has its own scope, and any variable declared within that function is only accessible to that function. However, a global variable can be used inside a function, unless another variable with the same identifier is used in that function.

Another particularity of Javascript is the fact that it doesn’t have a block-level scope. A block-level scope means that if a variable is declared inside a block (for, while, if, etc), it is accessible only there and not outside of it. For example, you may expect that this code will work as intended:

1
2
3
4
5
6
7
8
9
10
11
matrix = [[1,2,3], [4,5,6], [7,8,9]];
function print_matrix(matrix, n) {
for (var i = 0; i < n; ++i) {
row = matrix[i];
for (var i = 0; i < n; ++i) {
console.log(row[i]);
}
}
}
print_matrix(matrix, 3);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

However, the variable i from the first for is reassigned every time in the second one and this function will exit after first row.

Note: With the purpose of solving this issue, in the latest version of Javascript (ECMAScript 6), the keyword let was introduced. A variable declared with let used inside a block, will have a block-level scope. So simply changing var to let in that example, will make it work.

1
2
3
4
5
6
7
8
9
10
11
12
matrix = [[1,2,3], [4,5,6], [7,8,9]];
function print_matrix(matrix, n) {
for (let i = 0; i < n; ++i) {
row = matrix[i];
for (let i = 0; i < n; ++i) {
console.log(row[i]);
}
}
}
print_matrix(matrix, 3);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Variable hoisting

Hoisting is a default behavior in Javascript and represents moving all the declaration of variable at the top of their scope before code execution. So it doesn’t matter where inside a function we declare a variable, the variable belongs to that scope from the beginning of execution context. However, the hoisting happens only for variable declaration, not variable assignment. So before reaching the line where the variable is explicitly assigned a value, the variable is undefined.

Let’s see an example:

1
2
3
4
5
6
7
function myFunction() {
console.log(myVar); // undefined
var myVar = 3;
console.log(myVar); // 3
}
myFunction();
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Because of hoisting, this function is equivalent to:

1
2
3
4
5
6
7
8
9
10
function myFunction() {
var myVar; // declaration hoisted at the top
console.log(myVar); // undefined - I didn't assign a value yet
myVar = 3; // the assignment is not hoister - only here I have a value for myVar
console.log(myVar); // 3
}
myFunction();
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

This apply to any variable and to functions expression as well. As you saw in the example, functions expression are very similar to an object literal.

However, there are are some subtle difference between function expression and function statements.

Remember:

-hoisting moves the declaration at the top, but not the initialization -before explicitly assign a value, the variable is undefined

Function expressions vs. function statements

Before moving any further, I have a confession to make. The eye-catching quote from the beginning of the article is incomplete. I left out a part of it. Let’s look at the full version:

“Functions are the very best part of JavaScript. It’s where most of the power and the beauty of this >language is. But, like everything else in JavaScript, they’re not quite right.” Douglas Crockford

Having two ways of declaring a function with very subtle differences is an example of ‘not quite right’.

The difference consists in how the browser loads them into the execution context. The function expression are loaded exactly like other variables. The are assigned a value (in this case the function object) when the compiler reaches that line of code.

Function declaration, however, loads before any code is executed. So, even if the function is declared bellow the line of code you call it, it will work.

Remember:

  • if you call function expression before declaring it, you’ll get an error
  • if you call a function statement before declaring it, it will work

Why there are two?

Fair question. The function declaration is the newest one (introduced in ECMAScript 3). It’s the more useful one. Let’s keep in mind that Javascript is the language of the browser and the browser is updated very rarely by the users. Many times, the new versions of browsers are reaching to the users only when they update their os. This is why backwards compatibility is vital.

Function structure

As we stated before, each function is an object from data type point of view. The function object has 3 very important properties that represent the identity of that function: this, arguments and prototype.

What is 'this'?

In a function call, ‘this’ is a reference to the object which made that call. The value of ‘this’ is assigned at function invocation. This way, the function is allowed to know which object is concerned with.

When a function is simply called from the global scope, ‘this’ will obviously point to the global scope itself. This turn out to be a great source of confusion, this is why, when running in strict mode, the value is undefined. Normally, you won’t use ‘this’ for such a function.

‘This’ is very useful for functions used as a method. This way, the method has access to the object properties.

1
2
3
4
5
6
7
8
var myObj = {
name: "John",
sayName: function(name) {
console.log("Hi, " + this.name); // 'this' points to myObj in this case
}
};
myObj.sayName();
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

‘This’ also has an important role when the function is used as a constructor. A constructor function doesn’t have anything special as a structure. It is a constructor when it’s called with the operator new. This operator, under the hood, creates a new object and passes it to the function via ‘this’.

1
2
3
4
5
6
function Car(name) {
this.name = name;
}
var myCar = new Car("Subaru");
console.log(myCar.name);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

In the example above, function Car is used as a function. It’s a common practice to declare it with capital letter in order to make it’s purpose obvious, but it’s nothing more than a simple function.

Behind the scenes, the following things are happening:

  • a new empty object is created
  • the function Car is called with ‘this’ bound to the new object (so the object will get the property name with value ‘Subaru’)
  • the new object is returned

Every function has access to .apply(), .bind() and call(), inherited from Array.prototype. They allow the function to be called with any value of ‘this’ explicitly set.

For a more in-depth look at ‘this’ have a look at this article.

Remember: There are 4 ways to call a function

  • function form (‘this’ will be the global object or undefined in strict mode)
  • method form (‘this’ will reference the object that made the call)
  • constructor form (‘this’ will be the new object)
  • apply/bind/call form (‘this’ is explicitly set)

Function arguments

As we saw before, the arguments provided at declaration are not a reliable source of information. The function can be invoked with a different number of arguments. If they are too many, the extra arguments are ignored. If they are too few, the missing values will be undefined.

Fortunately, the function’s arguments property help us here. It is an array-like object which contains the arguments provided at invocation. It is not a real array in the sense that it doesn’t inherit from Array.prototype and does not have access to the methods for manipulating the elements. What it does have, is the length property, which knows exactly how many were provided. The arguments are stored exactly like an array, with index starting from 0.

Although the arguments object is not read-only, it is highly recommended to don’t modify it. Changing the arguments object will affect the named parameters as well, which is a great source of confusion.

A common usage of it is to create function with an undefined number of arguments. For example, a function that returns the sum of its arguments:

1
2
3
4
5
6
7
8
9
10
11
function sum() {
var i;
var total = 0;
var n = arguments.length;
for (i = 0; i < n; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4)); // 10
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Remember:

  • arguments object are the only reliable source of information about what was provided at function >invocation
  • treat the arguments like a read-only structure

Function Prototype

Function’s prototype object has meaning only when the function is used as a constructor. It has key role in creating inheritance in Javascript. Through it, objects created with the same constructor can share the same properties and behavior.

Prototypical inheritance is a vast subject and it’s outside of the scope of this article. I covered it in a different article.

Final Words

Thank you for your time. I hope you will find this helpful.

If you want to explore further, here are some of my other articles regarding this topic:

More about prototypes and inheritance.

More about ‘this’.

More about scope and execution context.

If you enjoyed this, please subscribe to WeeklyWebWisdom for more similar articles!

Open Source Your Knowledge: become a Contributor and help others learn. Create New Content