Good Parts of JavaScript — Callbacks, Closure, and Modules
By: John Au-Yeung
Tags: Technology, Programming, Software Development, Web Development, JavaScript

Photo by Samuel Scrimshaw on Unsplash

JavaScript is one of the most popular programming languages in the world. It can do a lot and have some features that are ahead of many other languages.

In this article, we’ll look at ways to define and use callbacks, closures, modules in JavaScript apps.

Callbacks

Functions make dealing with discontinuous events easier.

We can use them to run some code after a fixed amount of time for instance.

Callbacks are functions that are passed into another function and called either synchronously or asynchronously.

An example of a synchronous callback call is the callbacks that we pass into array methods.

For instance, we can write:

const arr = [1, 2, 3].map(a => a ** 3);

The function a => a ** 3 is called synchronously as soon as map is called.

Callbacks can also be asynchronous. Async callbacks aren’t run until the code some amount of time after the function is called.

An example of an asynchronous callback is a callback we pass into the setTimeout function.

For example, we can write:

setTimeout(() => {

console.log('foo');

}, 100)

The code above calls the callback after 100ms.

Async callbacks are used in many places since JavaScript programs run in a single thread, so we run as much code asynchronously as possible to avoid blocking the program thread.

Module

Before JavaScript have modules official, we used to put private code inside closures to avoid exposing to the public.

For instance, we can write:

const module = (() => {

let value = 0;

return {

getValue() {

return value;

}

}

})()

In the code above, we created an IIFE which returns an object.

The object has the getValue method which returns the value of value , which is kept private.

We can’t access value , but we can call getValue() .

However, now that we have modules, we can use them instead.

For instance, we can define one as follows:

module.js

export const foo = 1;

const bar = 2;

export const getBar = () => bar;

index.js

import { getBar } from "./module";

console.log(getBar());

We export foo and getBar in module.js so that we can use them in index.js .

getBar can then be called in index.js .

We kept bar private but we that we can expose them if we want to.

Also, we can the whole one thing in a module as a default export.

For instance, we can write:

module.js

const bar = 2; export default {

getBar: () => bar

};

With default exports, we export one thing and we import it by writing:

import module from "./module";

console.log(module.getBar());

If we import default exports, we don’t put the curly braces.

Cascade

We can chain methods that return this in the method.

For instance, we can write:

const box = {

setHeight(height) {

this.height = height;

return this;

},

setWidth(width) {

this.width = width;

return this;

},

setLength(length) {

this.length = length;

return this;

},

}

Then when we call the methods as follows:

box.setHeight(100).setWidth(200).setLength(150);

We get:

{

"height": 100,

"width": 200,

"length": 150

}

As we can see, if we return this , then we can set update this the way we wish to and return it.

Then we can chain the methods in an object.

This lets us produce interfaces that are expressive.

We can do a little bit in each method and chain all the little actions together.

Photo by chuttersnap on Unsplash

Curry

Curry functions allow us to produce a new function by combining a function and an argument.

We can create a curry function to return a function that has some arguments applied and let us apply the remaining arguments by writing the following:

const curry = (fn, ...args) => {

return (...moreArgs) => {

return fn.apply(null, [...args, ...moreArgs]);

};

}

In the code above, we have the curry function, which takes a function fn and some arguments args after it.

Inside it, we return a function that returns fn with all the arguments from both functions applied to it.

This way, we first apply the arguments in args , then we apply the arguments in moreArgs to fn .

Now if we call it as follows:

const add = (a, b, c) => a + b + c; const curried = curry(add, 1);

const result = curried(2, 3);

We first get a function with 1 applied to add in curried .

Then we get the final sum by applying 2 and 3 to curried .

Therefore, result is 6.

Conclusion

Callbacks are frequently used in JavaScript. There can be synchronously or asynchronously called.

We can define modules with official modules or IIFEs that return an object.

Currying functions let us return a function that have arguments partially applied and can apply more arguments later.

JavaScript In Plain English

Enjoyed this article? If so, get more similar content by subscribing to our YouTube channel!