javascriptclosuresfirst-class-functions

Difference between a closure and the funarg problem?


I have a misunderstanding: is the strainer function an example the downward funarg problem? I was using Chrome debugger under the "Sources" panel and noticed this under the "Scope" section:

screenshot of my description

Is the strainer function parameter cb a closure or is the function strainer the closure? I'm finding it difficult to sort through the information about closures and the funarg problem on the web. I clearly don't understand the funarg problem or closures and need some help.

function strainer(collection, cb) {
  return collection.reduce(function inner(acc, curr) {
    if (cb(curr)) {
      return acc.concat(curr);
    }
    return acc;
  }, []);
}

function even(number) {
  if (number % 2 === 0) {
    return true;
  }
  return false;
}

var collection = [1, 2, 3, 4, 5];

strainer(collection, even);

Background: I was under the impression private variables returned to an outer environment created closures but the example looks like something different.

The flintstones function example below has closure over the scope of the quotes function (I think this is the upward funarg problem).

function quotes() {
  var x = 'yabba dabba doo!';
  return function flintstones() {
    return x;
  }
}

var fredSays = quotes();
fredSays();


Solution

  • Is the strainer function param cb a closure or is the function strainer the closure?

    Neither, actually. inner is the closure. You are inspecting the scope chain of inner here - it has local acc and curr variables, and free variable cb that closed over the cb variable from the strainer scope. That's what the debugger is trying to show you. The cb part of the strainer scope is not allocated on the stack but in the heap, however the debugger doesn't display that detail.

    Yes, this is more or less the downward funarg problem. inner is passed to reduce here, and that's why we create a closure for it. Notice that the distinction between upward and downward is meaningless in JS, since we never know what the called function does with the passed callback - it might as well stow it away somewhere. Proving that it stays contained in and does not escape the call is not done.