Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "return () => local;" do in this closure?

I'm learning javascript by reading "Eloquent Javascript" and am confused by the "Closures" section in chapter 3 (Functions).

In previous sections I learned about arrow functions, and how they can be used as anonymous functions. My initial thoughts were that this is an anonymous function example and I am simply not familiar yet.

In particular, I am confused on what "() => local" does to/for return.

function wrapValue(n) {
  let local = n;
  return () => local;
}

let wrap1 = wrapValue(1);
let wrap2 = wrapValue(2);
console.log(wrap1());
// → 1
console.log(wrap2());
// → 2

Here is a link to the chapter: Eloquent Javascript - Ch. 3 "Functions"

Thanks in advance!

like image 572
Tucker Avatar asked Dec 19 '18 23:12

Tucker


2 Answers

In javascript function create scope. For example:

function scoped(){
  let local = 10;
  console.log(local) // this works local is within scope
}

scoped() // logs:

console.log(local) // error -- local doesn't exist out here.

Outside of scoped local doesn't exist.

A function inside a function has access to the entire scope. So this works:

function scoped() {
  let local = 10;
  function f() {
    console.log(local) // this works local is within scope
  }
  f()
}

scoped()

But what happens if you return that function that references the scope of the function? It turns out that the inner function carries the whole scope with it. This is a closure:

function scoped(){
  let local = 10;
  function f(){
    console.log(local) // this works local is within scope
  }
  return f
}

f = scoped()
f() // can still see local

// but nobody else out here can:
console.log(local) // still an error

This allows you to do some very slick things — an import one is that you can keep certain variables private, but still manipulate them with the closure.

For example here's a counter that doesn't require a variable in global scope:

function counter(){
  let count = 0
  return () => count++
}

let c = counter()

console.log(c())  // it can count but there's not count variable in scape
console.log(c())
console.log(c())

Doing this with a global count variable is messy and risks some other part of the code clashing with the global variable. Above, nothing other than the c function can access the counter. In fact you can make several independent ones:

function counter(){
  let count = 0
  return () => count++
}

let c = counter()
let d = counter()

console.log("c:", c())  // it can count but there's not count variable in scape
console.log("c:", c())
console.log("d:", d())  // d has it's own closure
console.log("d:", d())
console.log("c:", c())

There's a lot you can do with closures and they're important in Javascript. It's worth taking the time to really understand them.

like image 75
Mark Avatar answered Nov 11 '22 09:11

Mark


function wrapValue(n) {
   let local = n;
   return () => local;
}

Is the same as writing (without the benefits of "this")

function wrapValue(n) {
   let local = n;
   return function() {
        return local;
   }
}

It's a function that returns another function that uses the passed parameters. This is called a Curry function

console.log(typeof wrapValue(2)); // prints "function"
console.log(wrapValue(2)()); // prints "2"

Here's a better example

function multiple(a) {
    return (b) => a*b;
}

console.log([1,2,3,4].map(multiple(2)); // prints "[2,4,6,8]"

You can use curried functions very easily with Arrays

like image 37
Reactgular Avatar answered Nov 11 '22 07:11

Reactgular