30-seconds / 30-seconds-of-code

Short code snippets for all your development needs

Home Page:https://30secondsofcode.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Update What are JavaScript closures?

zhixiangteoh opened this issue · comments

I would like to add this to the discussion on closures in JavaScript, at What are JavaScript closures?; I can't seem to find where the source markdown is located:

One of the most classic examples of JavaScript closures is returning an inner function within some outer function, and then that inner function can be accessed anywhere outside of the outer function to indirectly access the variables and data in the outer function. In an object-oriented analogy, you can think of it like accessing private fields via an implicit getter method.

function outer() {
  const secretMessage = "You understand closures now!";
  return function inner() {
    return secretMessage;
  }
}

console.log(secretMessage); // error
console.log(outer()); // error
console.log(outer()()); // You understand closures now!

In this example, invoking outer returns the inner function object, which invoked in turn returns secretMessage. Here, inner serves as purely a getter method, as in our object-oriented analogy. In the following example, inner plays a more exciting role:

function curry(fn) {
  const args = [];
  // inner closes over args and fn
  return function inner(arg) {
    if (args.length === fn.length) {
      return fn(...args);
    }
    args.push(arg);
    return inner;
  }
}

function add(a, b) {
  return a + b;
}

// curry is invoked, returns inner to curriedAdd
const curriedAdd = curry(add);
// inner is invoked with multiple arguments, essentially one at a time
console.log(curriedAdd(2)(3)()); // 5

Code adapted from top-voted answer in this StackOverflow thread

In this example, the inner function inner (also curriedAdd) accesses the fn (also add) passed into the curry function, outside of the function definition. More interestingly, invoking inner with multiple arguments, one at a time, allows one to mutate the args array, defined within the curry function, outside of the function definition. It is so intuitive, yet so interesting. This is the beauty of closures!

I think the second example in the blog post covers the same ground even if the enclosed function is inside an object. Also, we try to keep blogs as brief as possible to keep readers engaged and allow for them to be used as a quick reference.