Function Expression
Named function expression's name can be used inside the function, as recursion.
IIFE
IIFE is a function that dies immediately after it came to life.
Using !
in front of function can enforce function expression, but can only use when we don't need return value.
!function sum(num1,num2){
console.log(num1+num2)
}(1,2);
The classical form is enclosing function with ()
.
(function sum(num1,num2){
console.log(num1+num2)
})(1,2);
Private & Public
Any variables that declared in side IIFE are not visible to outside world. It helps not polluting global scope.
However, IIFE can expose public function by returning it. So, we can access to pirvate variables through this public funciton. We call this function a Closures.
Classical modue pattern using IIFE & Closures
const Userlogin = (function login() {
const password = "password123";
return function check(input) {
if(input == password) {
console.log("authenticated");
} else {
console.log("wrong");
}
}
})();
Userlogin("password123"); // authenticated
check
fucntion is public, so it is accessible in global scope, but password
variable is private, which is not accessible.
Namespaces
Namespace is container of identifiers. We use namespaces to avoid collisons with outher identifiers in global namespace. **Namespacing **is an act of wrapping a set of entities, variables, functions, objects, under a single umbrella term.
Modules
IN ES6, built-in modules were finally introduced. Before ES6, developers used external libraries like CommonJS for modules. In ES6, Everything inside modules are private by default and it runs in a strict mode.
Benefits of using modules
- Code can be splitted into smaller files of similar functionality.
- Modules can be shared across number of applications.
As IIFE & Closures and Modules have same goal for using it, IIFE & Closure pattern could be replaced by ES6 modules.
Exporting & Importing
Single Export
// utils.js
function sum(num1, num2) {
return num1+num2;
}
function substract(num1, num2) {
return num1-num2;
}
export {sum,substract};
// main.js
import {sum,substract} from './utils.js';
console.log(sum(1,2));
// or
import * as utils from './utils.js';
console.log(utils.sum(1,2));
Named Export
// utils.js
export function sum(num1, num2) {
return num1+num2;
}
export function substract(num1, num2) {
return num1-num2;
}
Default Export
// utils.js
var utils = {
sum: function(num1, num2) {
return num1+num2;
},
substract: function(num1, num2) {
return num1-num2;
}
}
export default utils;
// main.js
import utils from './utils.js';
console.log(utils.sum(1,2));
import
and export
statements are hoisted, which acts like it's executed at the top of the program.
CommonJS vs ES6 modules
The biggest difference is 'how it works'. ES6 modules first parses, looks for imports, load and then exectues. On the other hand, CommonJS loads dependency on demand while executing.
// index.html
<script type="module" src="./a.js"></script>
// a.js
console.log('executing a.js')
import { helloWorld } from './b.js'
helloWorld()
// b.js
console.log('executing b.js')
export function helloWorld () {
console.log('hello world')
}
Above snippet works different in ES6 modules and CommonJS.
ES6 modules
executing b.js
executing a.js
hello world
CommonJS
executing a.js
executing b.js
hello world
Dynamic input()
So basically, in ES6, import
keyword is static. However, there is a way to use import
dynamically.
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
Dynamic import
returns promise
object of request module which is creted after fetching and evaluating module's dependency and itself. It can enhance the performance of the program.
Top comments (1)
I think "Classical modue pattern using IIFE & Closures" should be "Classical module pattern using IIFE & Closures"