8. IIFE, Modules, and Namespaces

16850 단어 JavaScriptJavaScript

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.

좋은 웹페이지 즐겨찾기