DEV Community

John Au-Yeung
John Au-Yeung

Posted on • Originally published at thewebdev.info

Object-Oriented JavaScript — Closures

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 an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at functions.

Functions that Return Functions

Fnctions can return functions.

For instance, we can write:

function a() {
  console.log('foo');
  return function() {
    console.log('bar');
  };
}
Enter fullscreen mode Exit fullscreen mode

We return a function and then we can call the function we return.

For instance, we can write:

a()();
Enter fullscreen mode Exit fullscreen mode

Then first call a , so 'foo' is logged.

Then we call the returned function with the second parentheses, so we get 'bar' logged.

Functions that Rewrites Itself

We should be aware that functions can rewrite themselves.

For instance, we can write:

function a() {
  console.log('foo');
  a = function() {
    console.log('bar');
  };
}
Enter fullscreen mode Exit fullscreen mode

Then we get 'foo' logged.

The first console log runs, then the function is reassigned.

We shouldn’t do that and linters will alert us if we do this.

Closures

Closures are functions that have other functions inside it.

The inner functions can access the outer function’s scope.

For instance, if we have:

function outer() {
  let outerLocal = 2;

  function inner() {
    let innerLocal = 3;
    return outerLocal + innerLocal;
  }
  return inner();
}
Enter fullscreen mode Exit fullscreen mode

We have the inner function with the innerLocal variable.

This is only available within the inner function.

It can also access the outer function’s outerLocal variable.

This is useful because we want to have private variables in our code.

We have outerLocal and innerLocal that are only available inner .

outer can’t access the variables of inner .

So we have different levels of privacy with these functions.

Closures in a Loop

If we have a loop that looks like:

function foo() {
  var arr = [],
    i;
  for (i = 0; i < 3; i++) {
    arr[i] = () => i
  }
  return arr;
}
Enter fullscreen mode Exit fullscreen mode

Then if we call it:

const arr = foo();
for (const a of arr){
 console.log(a());
}
Enter fullscreen mode Exit fullscreen mode

then we get 3 from all the console logs.

This is because i is 3 when we assigned the added our function to arr .

var isn’t block-scoped, so we would get the last value of i instead of what’s in the loop.

To get the value of i from the loop heading to the function we assign, we write:

function foo() {
  var arr = [],
    i;
  for (i = 0; i < 3; i++) {
    ((j) => {
      arr[i] = () => j
    })(i)
  }
  return arr;
}
Enter fullscreen mode Exit fullscreen mode

Then we get 0, 1, and 2 as we expect.

We can also replace var with let to make i block-scoped and avoid this issue.

Getter and Setter

Getter functions return values and setters sets values.

We can put the getter and setter functions into a closure so that we can keep them private.

For instance, we can write:

let getValue, setValue;
(() => {
  let secretVal = 0;
  getValue = () => {
    return secretVal;
  };

  setValue = (v) => {
    if (typeof v === "number") {
      secretVal = v;
    }
  };
}());
Enter fullscreen mode Exit fullscreen mode

And we run a function to assign the getValue and setValue functions with functions.

getValue returns the value of secretVal and setValue sets it.

This way, we keep secretVal secret.

Conclusion

Closures are great for various applications.

It’s mostly to keep variables private, and we can also use them to bind variables values the way we expect.

Top comments (0)