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!
3 Answers 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
2 Comments
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.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
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
show(negate(isNaN, NaN));". I would sayshow(negate(isNaN)(NaN)). It's not a matter of passing extra arguments, rather passing them to different closures.