Skip to content

Latest commit

 

History

History
185 lines (142 loc) · 4.2 KB

README.md

File metadata and controls

185 lines (142 loc) · 4.2 KB

IIFEs, Closures, Modules

These are the syntactical gymnastics we have to go through to get useful OO stuff in js, such as

  • private state
  • public API
  • encapsulation (global state is bad. why???)
  • namespacing

Pertinent js recap

  • js only has function scope
  • In js, functions are first order objects
    • functions can be passed as params
    • functions can be returned as the result of expressions
    • variables can hold functions
  • Functions are invoked with ()
  • Anything wrapped in () becomes an expression

Function declaration and invocation

// function declaration
function someName() { 
  // ...
}
// function expression
// (defines an anonymous function and assigns it to a var)
var someName = (function() {
  // ...
});
// function invocation
someName();

IIFE (iffy)

This is an IIFE

(function() {
  //...
})();
  • An anonymous function expression
  • The parens around the declaration turn it into an expression
  • The parens at the end cause it to be immediately invoked
  • Avoids polluting global scope
  • Allows us to hide private state
  • Avoids variable hoisting
(function() {
  var something = "my internal stuff";
  //...
})();

// what will the following line log?
console.log(something);

Closures

  • In js, if we use the function keyword inside another function, we are creating a closure
  • The local variables in the inner function can remain accessible after returning from the outer function
  • A closure is a function having access to the parent scope, even after the parent function has closed
  • A closure is a special kind of object that combines two things: a function, and the environment in which that function was created
  • Environment consists of any local variables that were in-scope at the time that the closure was created
var returnData = (function() {
  // only created once
  var largeDataSetTakesForeverToGet = [1,2,3]; // this could be an ajax call
  
  return function() { 
    console.log(largeDataSetTakesForeverToGet) 
  };
})();

// getting that same variable back each time
returnData();
returnData();
returnData();
  • This internal state can be mutable, but only through API we provide
var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();

add();
add();
add();

Closure as function factory

  • We can initialize a closure with state
  • A closure with its own state is created for each function invocation
function messageAfter(seconds) {
  return function(thingToMessage) {
    return 'Waited ' + seconds + ' seconds to say: ' + thingToMessage;
  };
}

var messageAfter5Seconds = messageAfter(5);
var messageAfter2Seconds = messageAfter(2);

messageAfter5Seconds("pocket gophers");
messageAfter2Seconds("pocket gophers");

messageAfter(7)("pocket gophers");
messageAfter(453764576)("pocket gophers");

JS Module Pattern

  • We can use IIFEs and closures as building blocks for modules
  • We can hide internal state
  • We can expose a public API
  • We can provide namespacing
  • This is a standard pattern for writing JS libraries
// mathy.js
var mathy = (function() {
  
  var topSecret = "shhhhhh";
  
  var factorial = (function(n) { 
    return Math.factorial(n);
  });
  
  var square = (function(n) {
    console.log("square");
    secretFunctionTime();
    console.log("square out");
    return n*n;
  });
  
  var log = (function(n) {
    return Math.log(n);
  });
  
  var secretFunctionTime = (function() {
    console.log(topSecret + ", can't call this from outside");
  });
  
  return {
    factorial: factorial,
    square: square,
    log: log
  }
})();
// ...
// > mathy.square(4);
// 16
// > mathy.secretFunctionTime
// undefined
// > mathy.topSecret
// undefined

Resources