A function statement

1
2
3
function add(a,b){
  return b+a;
}

Function expressions

1
2
3
var add = function(a,b){
  return a+b;
}
1
2
3
4
5
var factorial = function factorial(n) {
  if(n <= 1) return 1;
  return n * factorial(n -1);
};
console.log(factorial(3));

self-invoking function expressions

1
2
3
(function() {
  console.log("Hello There");
})();

Functions example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var validateDateForAge = function(data) {
  person = data();
  console.log(person);
  if (person.age < 1 || person.age > 99){
    return true
  }else{
    return false;
  }
};

var errorHandlerForAge = function(error){
  console.log("Error with age");
};

function parseRequest(data, validateData, errorHandler){
  var error = validateData(data);
  if (!error){
    console.log("Ok");
  }else{
    errorHandler();
  }
};

var generateDataForDrummer = function(){
  return {
  name: "Neil Peart",
  age: Math.floor(Math.random()* (100 -1)) + 1
  };
} ;
var generateDataForBassPlayer = function(){
  return {
  name: "Felipe Gomez",
  age: Math.floor(Math.random()* (100 -1)) + 1
  };
} ;

parseRequest(generateDataForBassPlayer, validateDateForAge, errorHandlerForAge);
parseRequest(generateDataForDrummer, validateDateForAge, errorHandlerForAge);

IIFE

1
2
3
4
(function() {
  var a = 6;
  console.log(a);
  })();

Douglas Crockfords IIFE

1
2
3
4
(function() {
  var a = 6;
  console.log(a);
}());

With parameters

1
2
3
4
(function(b) {
  var a = 2;
  console.log( a + b);
})(5);

WTF AGAIN

variables and function declarations are moved up during compilation fase(hoisting). Assignment or other logic are left in place.

1
2
3
a=1;
var a; // is this line hoisted to the top first?
console.log(a); // 1

function declaration hoisting

1
2
3
4
5
foo();
function foo(){  //hoisted. This way can be used before defining it
  console.log(a); //undefined
  var a = 1; // hoisted to the top of the foo() scope
}

Hoisting is made by scopes. So variables and function declaration are hoisted te the top of their scope

1
2
3
4
5
6
7
8
functionOne();
var functionOne = function(){
  console.log("FN1") // Error!
};
functionTwo();
function functionTwo(){
  console.log("functionTwo");
};

function declarations are hoisted first, then variable declarations

Danger Zone Never do this!! Browsers behave differently

1
2
3
4
5
6
if (true) {
  function say(){ return "true"}
}else {
  function say(){ return "false"}
}
say();

better apprach with function expresions

1
2
3
4
5
6
7
var sayMoo;
if (true) {
  sayMoo = function(){return 'true'};
} else {
  sayMoo = function(){return 'false'};
};
sayMoo();

function declatations are allowed to appear only in the program or function body. Blocks can only contain statemens and not function declarations. It is always advisible to not use function declarations in conditional blocks

Arguments parameter

Hint! Never name a parameter arguments. This would overide the original one.

1
2
3
4
5
6
7
8
var logSum = function(){
  var i, total = 0;
  for (i =0; i < arguments.length; i += 1) {
    total += arguments[i];
  };
  console.log(total);
};
logSum(1,2,3,4,5,6); // 21

Convert the arguments parameter to a real array

1
  var args = Array.prototype.slice.call(arguments);

Constructor preview

1
2
3
4
5
6
7
8
var Person = function(name){
  this.name = name;
};
Person.prototype.greet = function(){
  return this.name;
};
var robert = new Person("Albert F. Collins")
console.log(robert.greet());

Function Methods

As objects they have some methods, like apply() with two parameters, the first provides the context, and the other and array of values used as invocation arguments. call() is almost the same, but arguments are passed directlyin the arguments list.

Anonymous functions in objects

1
2
3
4
5
6
var momis = {
  say: function(){
    console.log('Hola Sebi');
  }
}
momis.say();

Anonymous functions as a parameter to other function

1
2
3
4
5
6
function eventHandler(event){
  event();
}
eventHandler(function(){
  console.log("Event fired!");
})

Closures

Closure is the scope created when a function is declared. It allows the function to access and manipulate variables that are external to this function. In other words, they allow a function to access all the variables, and other functions, that are in scope wjen the function itself is declared.

1
2
3
4
5
6
7
8
9
10
11
12
13
var outer = "Outer";
var copy;
function outerFn(){
  var inner = "Inner"
  function innerFn(){
    console.log(outer);
    console.log(inner);
  }
  copy = innerFn;
}
outerFn(); //Outer
copy(); // Inner
innerFn(); // innerFn is not defined

All variables in an outer scope are included in the scope, enven if they are declared after the function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var outer = 'outer';
var copy;
function outerFn(){
var inner = "inner";
  function innerFn(params){
    console.log(outer);
    console.log(inner);
    console.log(params);
    console.log(magic);
  };
  copy = innerFn;
};
console.log(magic); // magic is not defined
var magic = "Magic";
outerFn();
copy('copy');

Common closure patterns

1
2
3
4
5
6
function delay(message){
  setTimeout(function timerFn(){
    console.log(message); // The scope for timerFn can access the message variable
  },1000);
}
delay('Hello there')

To allow encapsulation

1
2
3
4
5
6
7
8
9
function PrivateTest(){
var results = 0;
  this.getResults = function(){ return results; };
  this.setResults = function(){ results++; }
}
var private = new PrivateTest();
private.setResults();
console.log(private.results); //undefined
console.log(private.getResults());// 1

Loops and closures

Wrong implementation

1
2
3
4
5
for(var i=1; i<=5; i++){
  setTimeout( function delay(){
    console.log(i);
  },i*100);
}

Right way The use of an iife inside each iteration creates a new scope for each iteration, and updates de local copy with the correct value.

1
2
3
4
5
6
7
for (var i=1; i <= 5; i++) {
  (function(j){
    setTimeout( function delay(){
      console.log(j);
    }, j*100);
  })(i);
}

Modules

1
2
3
4
5
6
7
8
var moduleName = function(){
  // private state
  // private functions
  return {
    // public state
    // return public variables
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var   superModule = (function(){
  var secret = "supersecretkey";
  var password = 'duke';

    function getSecret() {
      console.log( secret);
    };

    function getPassword() {
      console.log(password);
    }

  return {
    getSecret: getSecret,
    getPassword: getPassword
  };
}());
superModule.getSecret();
superModule.getPassword();