NTUI
NTUI

Reputation: 329

JavaScript: Anonymous vs Helper function

I'm trying to understand this functional style code from the book Eloquent Javascript:

http://eloquentjavascript.net/chapter6.html#exercise1

When the count() function passes an anonymous function to reduce() the code works. But if I break the function out into a helper function then I get a reference error.

Can anyone explain why count() works but countHelper() does not?

var numbers = [1,2,3,0,1,2,3,0]

function forEach(array, action) {
  for (var i = 0; i < array.length; i++)
    action(array[i]);
}

function reduce(combine, base, array) {
  forEach(array, function (element) {
    base = combine(base, element);
  });
  return base;
}

function equals(x) {
  return function(element) { return x === element;};
}

function count(test, array) {  
  return reduce(function(base, element) {
    return base + (test(element)?1:0);
  }, 0, array);
}

function countHelper(test, array) {
  function helper(base, element) {
    return base + (test(element)?1:0);
  }
  return reduce(helper(base, element), 0, array);
}

function countZeroes(array) {
  return count(equals(0), array);
}

print(countZeroes(numbers)) // 2

function countZeroesHelper(array) {
  return countHelper(equals(0), array);
}

print(countZeroesHelper(numbers)) // ReferenceError: base is not defined

Upvotes: 3

Views: 5884

Answers (1)

jfriend00
jfriend00

Reputation: 707218

In countHelper(), you are actually calling the helper function immediately when you pass arguments to reduce() and passing its return value to reduce (which isn't what you want), rather than passing a reference to the function so reduce() can call the function when it wants to. You have this:

function countHelper(test, array) {
  function helper(base, element) {
    return base + (test(element)?1:0);
  }
  return reduce(helper(base, element), 0, array);
}

It should be this:

function countHelper(test, array) {
  function helper(base, element) {
    return base + (test(element)?1:0);
  }
  return reduce(helper, 0, array);
}

Note the difference in arguments to the reduce() function.

When you want to pass a function as an argument, you don't include the parens after it because that just causes it to be executed right away and passes the return value from executing it rather than just passing a reference to the function itself.

This is a common mistake in an untyped language like Javascript that lets you pass anything in any argument. Even seasoned programmers occasionally make this mistake (myself included). The important distinction to understand is the difference between executing the function vs. passing a reference to the function.

Upvotes: 8

Related Questions