0

In the Flatiron lesson I'm doing on closures, there is the following example:

function retailPriceMaker(manufacturePrice) {
  return function(marketMultiplier) {
    return marketMultiplier * manufacturePrice;
  };
}

const retailPriceForNine = retailPriceMaker(9);

retailPriceForNine(2);
// 18

The lesson of course talks about how when the function inside retailPriceMaker is declared, the closure has access to (closure over) the variables in its scope, i.e., manufacturePrice, and retains it even when it's called, later.

I do understand this, as much as it makes my brain hurt.

One way that makes it a lot simpler for me is to think of it this way:


retailPriceMaker(9) returns the following function:

function(marketMultiplier) {
    return marketMultiplier * 9; 
  };

Where the fact that there was ever a variable called manufacturePrice does not matter and might as well be erased from the returned function's history books.

The idea that a closure "writes in" the values that are passed to it, rather than thinking of the variables/arguments being referenced in seeming absentia, is a LOT easier to wrap my head around.

So my question is: is this a valid way to think of closures, or am I missing something? It does seem a little too simple, and I would assume that if my explanation were completely valid:

  1. Closures would indeed be taught this way
  2. The JavaScript console would show the "filled in" function when you call the returned function:
function retailPriceMaker(manufacturePrice) {
  return function(marketMultiplier) {
    return marketMultiplier * manufacturePrice;
  };
}

const retailPriceForNine = retailPriceMaker(9);

retailPriceForNine;
// ƒ (marketMultiplier) {
//    return marketMultiplier * 9;
//  }

So, what, if anything, am I missing? Or have I just turned everyone's world upside down? (highly, completely unlikely)

Jonathan Tuzman
  • 11,568
  • 18
  • 69
  • 129
  • 3
    Possible duplicate of [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – MTCoster Feb 13 '19 at 22:03
  • As another resource I've written an article explaining closures - https://medium.com/@r.henry1989/javascript-what-is-closure-81c0d2b74916 – user3927582 Feb 15 '19 at 10:18

2 Answers2

2

No, this is too simple. Sure, in many cases the closed-over variable is a constant, and might as well be filled in. But in general, you need to consider that it is closing over a mutable variable:

var count = 0;
function increment() { // yes, this is a closure as well - `count` is in its scope
  count++;
}

console.log(count);
increment();
console.log(count);
increment();
console.log(count);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • "But in general, you need to close over a **mutable** variable" - I suppose that's your personal preference. Closures over immutables are fine and I see them a lot. – Alex Yu Feb 13 '19 at 22:48
  • @AlexYu Sorry for the incomprehensible phrasing, edited. It was never my intention to advise using mutable variables... – Bergi Feb 13 '19 at 22:51
0

Closures are in fact very simple concept with powerful consequences.

I'm not an historian of programming languages and cannot provide comparative analysis in different languages but I suppose they are everywhere almost the same as was defined in Scheme specification in 1975 by Sussman and Steel.

So how do we can describe closure in most simple way?

Very simple explanation from interpreter point (although maybe not "mathemathically" correct)

It's just a trick that allows to "break the rules" of variable lifecycle.

Let's look at your example:

/* 1. Each function have an own "namespace" where variables lives
   2. After `return` from a function it's namespace *must* be destroyed in "normal" cases 
      and every value *must* be deallocated */
function retailPriceMaker(manufacturePrice) { 
    /* 3. manufacturePrice - *must* be deallocated 
     after return from retailPriceMaker */
    return function(marketMultiplier) { 
    /* 4. But closures allows to "break" this rule 
          and languages that supports closures 
          do not deallocate "closed" values */
      return marketMultiplier * manufacturePrice; 
    };
    /* 5. manufacturePrice value here remains closed 
         and not deallocated after return */
}

Everything becames much more simpler if you think about allocations and deallocations.

Just note that:

  1. Without closures interpreter must destroy value after return from function
  2. Closures allows to "break" this rule. "Closed" values are not destroyed after return
  3. This "trick" is very simple itself but very powerful
Alex Yu
  • 3,412
  • 1
  • 25
  • 38