6

In http://eloquentjavascript.net/1st_edition/chapter6.html, there is the following example:

function negate(func) {
  return function(x) {
    return !func(x);
  };
}
var isNotNaN = negate(isNaN);
alert(isNotNaN(NaN));

Knowing only basic JavaScript and imperative programming, I am stumped by this programming style. What happens during runtime?

I stepped through the code and inspected variables and found that the value of x is NaN. How does it know that the argument to isNaN should be passed as argument x of the anonymous function? In the first place, why does the actual parameter NaN of isNotNaN become the argument to isNaN (ie while isNaN expects an argument, why does it take it from the argument of isNotNaN)?

2
  • "In the first place, why does the actual parameter NaN of isNotNaN become the argument to isNaN" Because of the third line: func(x). func is a reference to isNaN and x is NaN. This is not much different from any other function E.g. in function foo(x) { return bar(x); }; foo(x), foo passes x along to bar. The only difference in your example is that func is determined dynamically. Commented Sep 19, 2015 at 15:53
  • note this function negate correctly work only with functions that takes just one parameter Commented Sep 19, 2015 at 15:54

3 Answers 3

1

Best way to understand this might be with seeing what these things actually equal. Notice how func becomes the passed isNaN function.

function negate(func) {
  return function(x) {
    return !func(x);
  };
}
var isNotNaN = negate(isNaN);
/*

isNotNaN = function(x){
   return !isNaN(x)
}

*/

alert(isNotNaN(NaN));
Sign up to request clarification or add additional context in comments.

2 Comments

That comment block is enlightening. However, where does the value of x come from when isNotNaN is invoked?
@OldGeezer: In the last line: isNotNaN(NaN). You are passing NaN,
0

Notice that negate both accepts a function as an argument and returns a function. The returned function will call the argument function, negating the return value. Thus, isNotNaN is a function. When it is called, it will call the function originally passed into negate, in this case isNaN. Whatever you call isNotNaN with will be passed to isNaN.

In essence, you're configuring a function with another function. This might be easier to see with a simpler (no argument function) example:

function addX(x) {
    return function(y) {
        return x+y;
    };
}

var add2 = addX(2);
console.log(add2(2)); // 4

var add3 = addX(3);
console.log(add3(7)); // 10

Now, take this one step further and imagine you passed a function into addX instead of a value.

By the way, this is called currying.

Comments

0

It is because you set this:

   var isNotNaN = negate(isNaN);

And when calling isNotNaN(x)so it is like you call negate(isNaN)(x). You can also use a named function instead of the anonymous here so we say:

    function negate(func) {
      return xValue.call(this, x); //to be in the context of the xValue function
      };
   }
    var isNotNaN = negate(isNaN);
    alert(isNotNaN(NaN));

    function xValue(x) {
       return !func(x);
    }

    But then you have to take care about the context.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.