Named function expression's name can be used inside the function, as recursion.
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);
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.
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.
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.
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.
As IIFE & Closures and Modules have same goal for using it, IIFE & Closure pattern could be replaced by ES6 modules.
// 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));
// utils.js
export function sum(num1, num2) {
return num1+num2;
}
export function substract(num1, num2) {
return num1-num2;
}
// 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.
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.
executing b.js
executing a.js
hello world
executing a.js
executing b.js
hello world
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.