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.
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.