How JavaScript Closure is used in real life project ?

papercoding22

Paper Coding

Posted on February 12, 2021

How JavaScript Closure is used in real life project ?

Alt Text

First things first, what the duck is Closure ? 🦆Wack

I wrote a small example here "How to explain Javascript Closure for 5 years old kid":

So, if you are new to Javascript or never heard or not really understand what the "duck" is Closure, you need to go to back and eat that duck first.

HTML & Pure JS

Let's see a small example from MDN Web Docs

// CSS File
body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}
h2 {
  font-size: 1.2em;
}
Enter fullscreen mode Exit fullscreen mode
// HTML File
<p>Some paragraph text</p>
<h1>some heading 1 text</h1>
<h2>some heading 2 text</h2>

<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>
Enter fullscreen mode Exit fullscreen mode
// JS File
function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
Enter fullscreen mode Exit fullscreen mode
  • This code snippet above is how basically closure is applied in web development.
  • size12, size14, and size16 are predefined functions that resize the body text to 12, 14, and 16 pixels, respectively.
  • makeSizer activates "Closure in Javascript" and holds the size for each function. Now we attach them to buttons

In JavaScript, closures are created every time a function is created, at function creation time.

⇒ We have 3 closures are created and each one of them holds their own size.

React

  • Continuing with the above example, it will often be used in React as well.
function SizeButtons(props) {
  const listSize = props.listSize;
  const listItems = listSize.map((size) => {
        const handleOnClickItem = () => {
            document.body.style.fontSize = size + 'px';
        }
    return (<button onClick={handleOnClickItem}>{size}</button>);
    });

  return (
    <div>{listItems}</div>
  );
}

export default function App() {
  return (
    <div className="App">
      <p>Some paragraph text</p>
      <h1>some heading 1 text</h1>
      <h2>some heading 2 text</h2>
      <SizeButtons listSize={[12, 14, 16]} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • Try it at codesandbox
  • So we have an array listSize is passed as a prop into SizeButtons to render the list of size button.
  • We use JavaScript map to loop through the array and at each item, we return <button> element for each item.
  • Finally, we assign the resulting array of elements to listItems:
  • In mental modal, listItems looks like this [renderButton12, renderButton14, renderButton16], which means 3 functions to render 3 buttons. And in each function, the size value is attached.
  • So a closure is created every time the callback function is called from map
  • And at this case we have three closures, right !
  • This one is similar to the first example, but it is written in a bit different way.
  • So let's try to re-write and translate it to exactly similar way to the first example with HTML & Pure JS:
import "./styles.css";

const makeSizeButton = (size) => {
  return function() {
        document.body.style.fontSize = size + "px";
    }
};

function SizeButtons(props) {
  const listSize = props.listSize;
  const size12 = makeSizeButton(listSize[0]);
  const size14 = makeSizeButton(listSize[1]);
  const size16 = makeSizeButton(listSize[2]);

    const button12 = <button key={12} onClick={size12}>{listSize[0]}</button>
    const button14 = <button key={14} onClick={size14}>{listSize[1]}</button>
    const button16 = <button key={16} onClick={size16}>{listSize[2]}</button>

  const listItems = [button12, button14, button16];

  return <div>{listItems}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Redux

  • This simplified snippet code of Redux createStore function, but I will remove a bit its code in order to focus on what we are focusing "Closure"
// createStore.js
function createStore(reducer, initialState) {
  var currentReducer = reducer;
  var currentState = initialState;
  var listeners = [];
  var isDispatching = false;

  function getState() {
        // ...
  }

  function subscribe(listener) {
    // ...
  }

  function dispatch(action) {
    // ...
  }

  function replaceReducer(nextReducer) {
    // ...
  }

  dispatch({ type: '@@redux/INIT' });

  var store = { dispatch, subscribe, getState, replaceReducer };
    return store;
}

const store = createStore(...);
Enter fullscreen mode Exit fullscreen mode

Why closure is used here ?

As Redux official document says:

A store holds the whole state tree of your application. The only way to change the state inside it is to dispatch an action on it.

  • This means currentState of createStore is inviolable 🏰, it is inaccessible from outside, only inside createStore function can access and update it.
  • The createStore only returns a method to update the state is dispatch, and of course, it will rule how dispatch works. 🤴
  • We— "application developers" have to follow the rule.
  • So closure allows us to emulate private methods, and properties inside a function scope, because JavaScript does not provide a native way of doing this like Java, C# or some other class-based programming languages.

How about without Closure ?

// Without closure
function createStore(reducer, initialState) {
  const store = {};
  store.currentReducer = reducer;
    store.currentState = initialState;
    store.listeners = [];
    store.isDispatching = false;
  store.getState = function() {
    // ...
  };
    store.dispatch = function() {
        // ...
    }

    // ...
  return store;
}

const store = createStore();
// It allows us to mutate the store
// Which is anti-pattern i
store.currentReducer = null;

Enter fullscreen mode Exit fullscreen mode

So in conclusion:

Closures are useful because they let you associate data (the lexical environment) with a function that operates on that data. This has obvious parallels to object-oriented programming, where objects allow you to associate data (the object's properties) with one or more methods.

Express.js Middleware

  • Almost common middleware libraries out there are written in "Style of Closure" . Ex: cors, morgan, compression
  • For example: a code snippet inside compression middleware source code
function compression (options) {
  var opts = options || {}

  // options
  var filter = opts.filter || shouldCompress
  var threshold = bytes.parse(opts.threshold)

  if (threshold == null) {
    threshold = 1024
  }

  return function compression (req, res, next) {
        // ....
    }

}
Enter fullscreen mode Exit fullscreen mode
  • And how it is used in Express app
var express = require('express')
var cors = require('cors')
var app = express()

app.use(compression({
    // @TODO: Configure options here
}))
...
Enter fullscreen mode Exit fullscreen mode

Alt Text

  • Because middleware needs to store its options through the app's life cycle.
  • Whenever Express app call to the middleware, it needs to read the options was initially configured.

In collusion, most of the case, closure is used whenever we need to store something at the run time, such as app global data (Redux), configs, options (Express middleware) in private, or attach data to callback event (React), so that we can access it later when the functions are called to.

“Program to an interface, not an implementation.”
Design Patterns: Elements of Reusable Object Oriented Software

💖 💪 🙅 🚩
papercoding22
Paper Coding

Posted on February 12, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related