1

I'm new to Javascript, I'm self-teaching, so this might be an obvious area, but no matter how I phrase the question I can't really seem to get my head around this one issue. At the moment I'm reading through http://eloquentjavascript.net/chapter6.html (which was on mozilla's MDN). I've come across this a couple of times now, I would just like a simple break down if possible.

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

I don't understand how at the very last step isNotNaN (a variable) is passing an 'extra argument' (NaN) to the function stored in isNotNaN (negate(isNaN). "show(isNotNaN(NaN));"

I came across this same problem when the concept of enclosure was trying to be explained. But I don't get where this argument "NaN" is going in the above function, as it seems to me like the last statement ends up something like:

show(negate(isNaN, NaN));

I would be happy to provide more details. This concept of passing an extra argument to a variable already holding a function with an argument confuses the hell out of me!

1
  • "as it seems to me like the last statement ends up something like: show(negate(isNaN, NaN));". I would say show(negate(isNaN)(NaN)). It's not a matter of passing extra arguments, rather passing them to different closures. Commented Mar 20, 2014 at 9:09

3 Answers 3

3

There's no "extra" argument. The negate() function itself returns a function defined as a function expression, which can then be called with any number of original (not extra) arguments passed. A closure is used for the returned function to keep a reference to isNaN as func.

var isNotNaN = negate(isNaN);

At this point, isNotNaN contains a reference to the function

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

Again, func here refers to the isNaN argument passed to the negate function, which is the immediate parent in the scope chain. The result is similar, but not the same as

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

The reason it is not the same is, if we change the value of isNaN, the behaviour of this function will change. In the example you posted, however, the value of func is equal to the original value of isNaN and cannot be changed by anything outside of its scope thanks to the closure.

Essentially, you can pass in any function and get a new function that returns the negated result of the original function in return. For example:

var isNotArray = negate(Array.isArray);
isNotArray(12);
//-> true
Sign up to request clarification or add additional context in comments.

2 Comments

Excellent! I understand now a bit more when you say that isNotNaN evaluates to (something very similar to) the enclosed function. Also @Johan helped with his foobar function, however I see that in Johans final statement, rather than assigning a value to the argument through fooRef, he seems to assign two separate arguments to straight to foo: "foo(1)(2)" I presume here in his example the 1 assigns to (x) and the 2 assigns to (y)? If this is correct, is this not a better method than assigning foo(1) to fooRef then passing (2) to fooRef? Or is there something with closures here I'm missing?
@Bluey: you seem like you've just about got it :-) Neither method is necessarily better, they both have the same effect. You could say assigning the return value of foo(1) to fooRef is more readable, especially in cases where foo() might take a large number of arguments or a function itself as an argument.
0

In fact, negate(isNaN) simply return a function to the variable isNotNaN. This function take a parameter (named x in your case), then execute the function isNaN on the parameter before negating it and returning the result.

Comments

0

Perhaps this example can clear some things out for you regarding closures:

function foo(x){

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

    return bar;
}

var fooRef = foo(1); // fooRef references foo() with x set to 1

console.log(fooRef(2), foo(1)(2)); // 3, 3

http://jsfiddle.net/ePwy8/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.