[JavaScript] Functions

In JavaScript, a function is really a unique feature. In general, you can use it as a global module. Define it and use it anywhere you want. But JavaScript functions are much more than that. Let’s find out what they are.

Functions

A JavaScript function is a group of statements that can be run as a single unit. It has the following features:

  • can have parameters
  • returns a value
  • each invocation has a context value – can be accessed by “this
  • A function can be assigned to the property of an object, which is called a method. The invocation context of a method is an object. Therefore, the “this” keyword inside a method refers to the object itself.

Functions can also be designed to create objects. They are called constructors.

Functions as Objects

In JavaScript, a function is also an object. You can freely assign functions to variables or properties in objects. Interestingly, you can even add properties or methods to functions (rarely used, though).

var calculator = {
  x: 0,
  y: 0,
  add: function () { return this.x + this.y; }
};

calculator.x = 10;
calculator.y = 20;
alert(calculator.add());

Declaring Functions

Functions are defined by using the keyword “function” followed by a name, parameters, and statements. When functions are declared as part of an expression, the name of the function is usually omitted.

$(document).ready(function () {
  var nums = [1, 2, 3, 4, 5];
  alert(nums.reduce(function(r, v) { return r+v; }, 0)); // 15
});

Invoking Functions

There are a couple of ways to invoke or call functions:

  • as a function
  • as a method
  • as a constructor
  • indirectly using the “call()” or “apply()” methods

Constructor Invocation

When you call a function with the “new” keyword, a new object is created. Constructors initialize the properties of objects.

var now = new Date();
alert(now.toString());

The following example shows how a constructor is used to create a custom object.

function Calculator(x, y) {
  this.op1 = x;
  this.op2 = y;
}
Calculator.prototype.add = function () {
  return this.op1 + this.op2;
}
 
$(document).ready(function () {
  var calculator = new Calculator(10, 20);
  alert(calculator.add());
});

Indirect Invocation

Indirect invocation is used when you want to call a function as if it is a method of an object. You know each function has its own invocation context and can be accessed by “this. ” What if you want to call a function with the specific object context? That is for what indirect invocation is.

Function.prototype” defines the “call()” and “apply()” methods.

  • apply(thisArg, argsArray)
  • call(thisArg, arg1, arg2, …)

Two methods do the same task. The difference is how to pass arguments to a function. You need to use an array to the “apply()” method.

function calculateTax(rate, deduction) {
  var tax = (this.amount - deduction) * rate;
  return tax > 0 ? tax : 0.0;
}

When you call the “calculateTax()” function directly, you will get an error because the invocation context does not have an amount property.

function calculateTax(rate, deduction) {
  var tax = (this.amount - deduction) * rate/100;
  return tax > 0 ? tax : 0.0;
}
function Product(price) {
  this.amount = price;
}
 
$(document).ready(function () {
  var food = new Product(10);
  var truck = new Product(40000);
  alert(calculateTax.apply(food, [10, 100])); // 0
  alert(calculateTax.call(truck, 10, 10000)); // 3000
});

You can think of indirect invocation as a temporary method.

var truck = new Product(40000);
truck.calTax = calculateTax; // temporary method
alert(truck.calTax(10, 10000)); // 3000
delete truck.calTax; // remove it

Optional Parameters

You can invoke functions with fewer arguments than declared parameters. The important part is how to check whether the argument is passed or not.

When the arguments are not passed, matching parameters are set to “undefined. “

function add(x, y) {
  if (y === undefined) {
    y = 0;
  }
  if (x === undefined) {
    x = 0;
  }
  return x + y;
}

alert(add(10,20)); // 30
alert(add(10)); // 10
alert(add()); // 0

Variable Length Arguments and Variadic Functions

You can even pass more arguments than the number of parameters. And then how can we access the arguments? Actually, all arguments can be accessed through the “arguments” array-like object (It is not an array, which can be a language design mistake).

By using this “arguments” variable, you can create a function that can accept any number of arguments. This kind of function is called a variadic function.

function add() {
  var result = 0;
  for (var i = 0; i < arguments.length; i++) {
    result += arguments[i];
  }
  return result;
}

alert(add(1,2,3,4,5,6,7,8,9,10)); // 55

Return Values

In JavaScript, functions always return values. There is no “void” type. If you do not return a value in a function, the return value is “undefined. “

function dummy() {
};
 
var result = dummy();
alert( typeof result ); // "undefined"

Hoisting

Hoisting” means to lift someone or something to a higher place. JavaScript lifts (hoists) variables and functions to the top.

Scope

Variables in most programming languages are scoped in blocks { }. JavaScript does not have a block scope. Instead, it has a function scope.

{
  var i = 10;
}
alert(i);

It returns “10” even though “i” is defined in a block.

But if the variable is defined in a function, it is local to the function.

function doSomething(){
  var i = 10;
}
alert(i);

You will get an error “i is undefined.”

Variable Hoisting

Now you know variables are local in a function. But JavaScript engine hoists all local variables to the top. What does it mean?

(function () {
  alert(i); // undefined or 10 ???
  var i = 10;
})();

You will see the alert box with “undefined.” What does it mean? What has happened here?

Hoisting only lifts the declaration, not the value. The previous code is much like the following:

(function () {
  var i;
  alert(i); // undefined
  i = 10;
})();

This feature can make your code quite interesting when the local variable is mixed with the global one.

var i = 5; // global
(function () {
  alert(i); // undefined
  var i = 10;
  alert(i); // 10
})();

You might think the first alert(i) will show “5”. But it displays “undefined” because the local variable declaration is hoisted.

Note that only the declaration is hoisted; the value is not hoisted.

Function Hoisting without var

Functions are also hoisted in a global or function scope. You can call the function even before it is defined.

(function () {
  alert(add(2, 3)); // 5
 
  function add(x, y) {
    return x + y;
  }
})();

Function Hoisting with var

But if functions are assigned to variables using “var, “only declarations are hoisted. The function implementation is not hoisted.

alert(add(2, 3)); // error
 
var add = function (x, y) {
  return x + y;
}
 
alert(add(3, 4)); // 7

Closure

Function Closure is one of the most widely referred JavaScript techniques. It sounds complex, but once you have understood the concept, it becomes quite useful. Also, it is not as difficult as you might think.

Nested Functions

Functions can be nested. Variables in JavaScript are scoped in functions, and variables in outer functions can be accessed in inner functions. (Just like global variables in functions).

function outer() {
  var x = 10;
 
  inner();
 
  function inner() {
    var y = 20;
    alert(x + y);
  }
}
 
outer(); // call inner() and shows 30

There’s nothing new here.

Closure

Let’s change how to call the function a little bit.

function outer() {
  var x = 10;
 
  return function inner() {
    var y = 20;
    alert(x + y);
  }
}
 
var innerFunc = outer();
innerFunc(); // 30

The “innerFunc” variable refers to the inner function. When it is called, only “inner()” is invoked. The interesting thing is that “inner()” tries to access “x,” which is defined in “outer().” But you already executed “outer(),” which does not exist anymore.

But the result is still 30.

“Closure” means that the variable in the outer functions stays alive as long as the inner functions are alive.

Modules

You might wonder why “Closure” is an important concept in JavaScript in any way. I think people do not use nested functions often, not to mention closures.

One example of closure is a “Module. “A module is like a class on other languages. It hides its state and exposes its interfaces.

var Calculator = function (x, y) {
 
  // private members
  var _x = x,
      _y = y,
      _add = function () { return _x + _y; },
      _multiply = function () { return _x * _y; };
 
  // public interface as an object
  return {
    add: _add,
    multiply: _multiply
  };
}
 
var calc = new Calculator(3, 4);
alert(calc.add()); // 7
calc = new Calculator(5, 10);
alert(calc.multiply()); // 50

By using closures, you can simulate private members (variables in outer functions) and public interfaces (inner functions).

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s