Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Closures

Spread the love

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');
  };
}

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

For instance, we can write:

a()();

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');
  };
}

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();
}

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;
}

Then if we call it:

const arr = foo();
for (const a of arr){
 console.log(a());
}

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;
}

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;
    }
  };
}());

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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *