DEV Community

loading...

Functional JavaScript — Closures

aumayeung profile image John Au-Yeung Originally published at thewebdev.info ・2 min read

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to use closures.

Closures

Closures are inner functions.

An inner function is a function within a function.

For example, it’s something like:

function outer() {
  function inner() {}
}
Enter fullscreen mode Exit fullscreen mode

Closures have access to 3 scopes.

They include variables that are declared in its own declaration.

Also, they have access to global variables.

And they have access to an outer function’s variable.

For example, if we have:

function outer() {
  function inner() {
    let x = 1;
    console.log(x);
  }
  inner();
}
Enter fullscreen mode Exit fullscreen mode

then the console log logs 1 because we have x inside the inner function and we access it in the same function in the console log.

The inner function won’t be visible outside the outer function.

We can also access global variables within the inner function.

For example, if we have:

let global = "foo";

function outer() {
  function inner() {
    let a = 5;
    console.log(global)
  }
  inner()
}
Enter fullscreen mode Exit fullscreen mode

Then 'foo' is logged since inner has access to the global variable.

Another scope that inner has access to is the scope of the outer function.

For example, we can write:

function outer() {
  let outer = "outer"

  function inner() {
    let a = 5;
    console.log(outer);
  }
  inner()
}
Enter fullscreen mode Exit fullscreen mode

We have the outer variable and we access it in the inner function.

Closure Remembers its Context

A closure remembers its context.

So if we use it anywhere, the variables that are in the function are whatever they are within the original context.

For example, if we have:

const fn = (arg) => {
  let outer = "outer"
  let innerFn = () => {
    console.log(outer)
    console.log(arg)
  }
  return innerFn;
}
Enter fullscreen mode Exit fullscreen mode

Then the outer and arg variable values will be the same regardless of where it’s called.

outer is 'outer' and arg is whatever we passed in.

Since we return innerFn with fn , we can call fn and assign the returned function to a variable and call it:

const foo = fn('foo');
foo()
Enter fullscreen mode Exit fullscreen mode

We pass in 'foo' as the value of arg .

Therefore, we get:

outer
foo
Enter fullscreen mode Exit fullscreen mode

from the console log.

We can see that the values are the same even if we called it outside the fn function.

Real-World Examples

We can create our own tap function to let us log values for debugging.

For example, we can write:

const tap = (value) =>
  (fn) => {
    typeof(fn) === 'function' && fn(value);
    console.log(value);
  }

tap("foo")((it) => console.log('value:', it))
Enter fullscreen mode Exit fullscreen mode

to create our tap function and call it.

We have a function that takes a value and then returns a function that takes a function fn and runs it along with the console log.

This way, we can pass in a value and a function.

Then we get:

value: foo
foo
Enter fullscreen mode Exit fullscreen mode

logged.

The first is from the callback we passed in.

And the 2nd is from the function we returned with tap .

Conclusion

Closures are inner functions.

They have access to the outer function’s scope, global variables, and their own scope.

We can use it or various applications.

Discussion (0)

pic
Editor guide