Function

JavaScript divide functions into declarative and anonymous.

Declarative function

JavaScript interprets declarative functions only once when the page is loaded. The interpreted declarative function executes each time users call it. When you create a declarative function, you need to use the function keyword, function name, argument list, and function body as shown below:

function functionName (arg1, arg2,,,argN) {
  //Execution syntax
}
function add(a,b) {
  return a + b;
}
alert(add(3,4));

Anonymous function

An anonymous function is a function that is created dynamically at runtime.

var multiply = function(a, b) {
  return a * b
};
alert(multiply(3,4));

You can create an anonymous function using the Function's constructor. But this method is not used often.

var minus = new Function('a','b', 'return a - b');
alert(minus(3,4));

Self-Executing Anonymous Functions

If you put a function in parenthesis and lay another parenthesis right next to the closing parenthesis, the function inside the parenthesis runs immediately.

(function() {
  alert("Hello World!");
})();
(function(whom) {
  alert("Hello " + whom);
})('John Doe');
(function(a, b) {
  alert(a + b);
})(2,5);

Scoping and Hoisting

Scoping is a rule that determines the effective area of a variable.

Understanding scoping requires an understanding of hoisting. But, hoisting is not an official term in JavaScript.

Hoisting refers to the action of a JavaScript interpreter to 'raise a declared variable or function to the top of the current execution area.' The assignment statement is not subject to hoisting because the engine runs it at runtime.

In Java, variables declared in a block are valid only within a block. In JavaScript, however, you can only create such variables within a function. In other words, you can not create variables that are valid only in the {} and if statement blocks.

Predict the results of the following code.

var x = 1;
function fn() {
  if (true) {
    var x = 10;
  }
  alert(x);
}
fn();
var x = 1;
function fn() {
  x = 10;
  return;
}
fn();
alert(x);
var x = 1;
function fn() {
  x = 10;
  return;
  function x() {}
}
fn();
alert(x);

The identifier x of the fn() function is valid only within the fn() function. The JavaScript engine interprets the above source as follows.

var x = 1;
function fn() {
  function x() {}
  x = 10;
  return;
}
fn();
alert(x);

Predict the results of the following code.

var x = 1;
function fn() {
  function x() {}
  x = 10;
  return x;
}
var retVal = fn();
alert(retVal);
alert(x);

In JavaScript, you can not create variables that are valid only in the {} and if statement blocks.

var x = 1;
alert(x);
if (true) {
  var x = 2;
  alert(x);
  x++;
}
alert(x);
function foo() {
  var x = 1;
  if (x) {
    (function () {
      var x = 2;
      alert(x);
    }());
  }
  alert(x);
}
foo();

The declared variable x in the inner function of function foo is a new variable with a valid region within the internal function. It has no relation to the declared variable x in the outer function foo.

var x = 10;
function fn() {
  alert(x);
  var x = 20;
  alert(x);
}
fn();
alert(x);

The JavaScript engine hoists the above code as follows.

var x = 10;
function fn() {
  var x;
  alert(x);
  x = 20;
  alert(x);
}
fn();
alert(x);

Comment out the var x declared in the function fn() to see how the result changes.

Predict the results of the following code.

sayHo(); //SayHo() comes first in the code.
function sayHo() { 
  alert("Ho");
}

The JavaScript engine hoists the above code as follows.

function sayHo() { 
  alert("Ho");
}
sayHo();

The following code, which looks similar to the above, throws an error.

sayHo(); //TypeError: sayHo is not a function
var sayHo = function() {
  alert("Ho");
}

The following is more complicated.

function bumpInto() {
  function greet() {
    alert("How You Doin?");
  }
  return greet();
  function greet() {
    alert("What's Up?");
  }
}
bumpInto();

The JavaScript engine hoists the above code as follows.

function bumpInto() {
  function greet() {
    alert("How You Doin?");
  }
  function greet() {
    alert("What's Up?");
  }
  return greet();
}
bumpInto();

If the parameter list is different, will it overload as Java?

function bumpInto() {
  function greet() {
    alert("How You Doin?");
  }
  function greet(whom) { //Greet function with parameters
    alert("What's Up?");
  }
  return greet();
}
bumpInto();

JavaScript doesn't overload functions as Java does. The greet (whom) declared later is executed.

Remember that the assignment statement is not subject to hoisting because the engine runs it at runtime.

Predict the results of the following code.

function bumpInto() {
  var greet = function () {
    alert("How You Doin?");
  }
  return greet();
  var greet = function (whom) {
    alert("What's Up?");
  }
}
bumpInto();

The engine hoists and interprets the code as shown below.

function bumpInto() {
  var greet;
  var greet;
  greet = function () {
    alert("How You Doin?");
  }
  return greet();
  greet = function (whom) {
    alert("What's Up?");
  }
}
bumpInto();

After the return statement, the greet() function, which prints "What's Up?" has no chance to do it.

Closures

Inner function

JavaScript supports internal functions. An inner function can use variables declared in an outer function, which wraps the inner.

function fn() {
  var balance = 0; //outside variable
  function deposit(money) { //inner function
    balance += money;
    alert(balance);
  }
  deposit(100);
}
fn();

There is no way to call an internal function directly outside the parent function, but there is a way to execute the internal function outside the parent function.

A JavaScript function is an object, so you can assign a function to a variable or pass it as an argument to another function.

function fn() {
  var balance = 0; //outside variable
  function deposit(money) { //inner function
    balance += money;
    alert(balance);
  }
  alert("The fn() function is executed.");
  return deposit;
}
var retFn = fn();//If the function fn does not return, retFn is undefined.
retFn(200);

The above example shows how to use the inner function outside the parent function. The fact that this code runs without problems makes the Java programmer uncomfortable. In Java, local variables defined in a method disappear when the method terminates. But, the variable balance is still valid even though the fn() function ends.

Since the retFn has a closure, the variable balance is still valid. A closure is a peculiar object made up of two. The first is a function, and the second is an environment created by the function. The environment here means variables declared outside the function that is available by the function. The retFn has a closure containing the function deposit and the variable balance.

function fn() {
  var balance = 0;
  function deposit(money) {
    balance += money;
    alert(balance);
  }
  return deposit;
}

var ac1 = fn();
alert("---ac1---");
ac1(50);
ac1(450);

var ac2 = fn();
alert("---ac2---");
ac2(2000);
ac2(500);

JavaScript creates a closure when outside the function references the function's inner functions. You can call internal functions through a reference beyond its scope means that you can still call in the future, so JavaScript must keep this function. If a variable is a local variable of a parent function, the inner function inherits the parent's scope and can reference the variable. Calling deposit() twice with the same reference variable, you can see the accumulated balance. Also, the balance variables increase independently in calls to the deposit() function that use different reference variables (ac1 and ac2).

Shared variables between closures

function account(accountNo) {
  var balance = 0;
	
  function getAccountNo() {
    return accountNo;
  }
  function deposit(money) {
    balance += money;
  }
  function withdraw(money) {
    balance -= money;
  }
  function getBalance() {
    return balance;
  }
  return {
    "getAccountNo": getAccountNo,
    "deposit": deposit,
    "withdraw": withdraw,
    "getBalance": getBalance
  };
}

var ac1 = account('111');
ac1.deposit(1000);
ac1.withdraw(500);
alert(ac1.getAccountNo() + ': ' + ac1.getBalance());

var ac2 = account('222');
ac2.deposit(3000);
ac2.withdraw(1000);
alert(ac2.getAccountNo() + ': ' + ac2.getBalance());

ac1.deposit(1000);
ac1.withdraw(500);

The four internal functions share the local variables. If the deposit() function increments the balance by 1000, the increased balance will be the new starting value when you call the withdraw() again.

var ac2 = account('222');

When you call account() again, JavaScript creates a new closure instance with the closed environment.

Object-oriented coding in JavaScript

The following example is similar to the Account class in Java.

There is a 'prototype' property in JavaScript. The prototype property allows you to add a new property or function to an object.

function Account(accountNo,balance) {
  this.accountNo = accountNo.toString();
  this.balance = balance;
}
Account.prototype.getAccountNo = function () {
  return this.accountNo;
};
Account.prototype.getBalance = function () {
  return this.balance;
};
Account.prototype.deposit = function (money) {
  this.balance += money;
};
Account.prototype.withdraw = function (money) {
  this.balance -= money;
};

var ac1 = new Account('111',500);
ac1.deposit(1000);
ac1.withdraw(500);
alert(ac1.getAccountNo() + ': ' + ac1.getBalance());

var ac2 = new Account('222',1000);
ac2.deposit(3000);
ac2.withdraw(1000);
alert(ac2.getAccountNo() + ': ' + ac2.getBalance());
References