This is a problem from chapter 5 of Eloquent JS http://eloquentjavascript.net/05_higher_order.html
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(12);
// → calling with 0
// → called with 0 - got false
Can someone please explain how f(arg) makes sense? I mean he is calling the argument f on another argument arg?? I am very confused.
How about the part that has return val; Why does that have to be there? When I delete it, the code still runs like it should.
Lastly, can some explain the code interpretation line by line? How does passing boolean make sense in the example?
Thank you so much
One simple rule to remember is that nested functions in Javascript (e.g. functions declared within other functions) have access to all the variables and arguments of their parent functions.
When noisy(f) is called and it returns another function, that creates a closure in Javascript. That means that even though noisy(f) has finished execution, it's arguments and any local variables are still alive and can still be used by the inner function.
So, when that inner function is then called, it has full access to the f argument from the prior execution of its parent function. Here's an MDN reference on closures which might be worth reading and a StackOverflow answer explaining closures.
So, let's break down what your code is doing step by step:
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
// split up noisy(Boolean)(12); into two steps
var temp = noisy(Boolean);
temp(12);
When noisy(Boolean) is called, that returns the inner function and for any future invocation of that inner function, the f argument is set to the Boolean constructor function.
When that returned function is then called with it's own argument as in temp(12) above, then it ends up executing Boolean(12) and returning that (who's value will be true).
Working demo: http://jsfiddle.net/jfriend00/mkn839gu/
Basics:
noisy maps a function to another function that does the same as the original but writes input and output value ( moreprecisely their string representations) to the console.
Q1: The intention seems to be the enhancement of object constructors with a simple logging facility to show which initialization arguments produce which kind of object state. To this end, noisy returns a function object - the original function enhanced by output to the console.
Q2: The enhanced Boolean constructor is called without assigning its return value. Thus it makes no difference to the code whether the enhanced constructor does return a value or not.
Q3: Boolean reveals what boolean values you get for different initialization arguments. I guess the lesson to be learned is that a numerical of 0 gets you a false, anything else true (the latter is informed guessing on my part, but with noisy you have a tool to generically check that for arbitrary constructors and initialization values).
keeping it simple:
the argument in function noisy (that acts as a wrapper) is actually just
(Boolean());
(for ref on boolean-type check this).
Furthermore you use 0 as argument of console.log in the inner function,
and as the argument of Boolean() (in var val).
How about the part that has return val; Why does that have to be there? When I delete it, the code still runs like it should.
as long as you're using console.log you're not actually using the return statement, but if you were to do this
console.log(noisy(Boolean)(0))
you can see the return statement after the previous console.logs
Related
I am reading Eloquent JavaScript (The new edition) and I reached the part on higher order functions and I'm confused on what's happening in the following code.
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0);
// → calling with 0
// → called with 0 - got false
Why is the call to the function noisy like this? Is (Boolean) a cast? A cast for what? the return value? or the argument? why not (Boolean)noisy(0) if its the return value. Or noisy((Boolean) 0) if the argument is the one being casted.
noisy(Boolean)(0)
What is happening in this line? Where is f() even defined?
var val = f(arg);
Boolean is a function. It's the function you're calling indirectly through noisy. A bit confusing, I know, because it looks like the name of a type. But in JavaScript, those initially-capped things (Boolean, Number, String, and so on) are functions. When you call Boolean (without using new), it tries to convert the argument you gave it into a boolean primitive value and returns the result. (See §15.6.1 in the spec.)
f is the name of the argument in the noisy function.
Functions in JavaScript are first-class objects. You can pass them into other functions as arguments just like any other object.
When you do
noisy(Boolean)(0)
There are two things going on. First:
// (In effect, we're not really creating a variable...)
var x = noisy(Boolean);
That gives us a function that, when called, will call Boolean with the argument we give it while also doing those console.log statements. This is the function you see being created in noisy (return function(arg)...);
Then we call that function:
x(0);
And that's when you see the console output. Since Boolean(0) is false, you see Boolean return that value.
Here's a much simpler example:
function foo(bar) {
bar();
}
function testing() {
alert("testing got called");
}
foo(testing);
There, I'm passing the function testing into foo. The argument name I'm using for that within foo is bar. The line bar(); calls the function.
A function without the () is the actual function. A function with () is an invocation of the function. Also keep in mind that JavaScript is a loosely typed language, so you don't declare variable types. I've added some comments to your example to try and help.
// We define a function named noisy that takes in an argument named f. We are expecting f to be a function but this isn't enforced till the interpreter throws an error.
function noisy(f) {
// Noisy returns a single item, an anonymous function. That anonymous function takes in an argument named arg
return function(arg) {
console.log("calling with", arg);
// Our anonymous function then takes f (It can use f because its defined inside noisy, see closures for more details) and invokes it with the argument arg and stores the result in a variable named val.
var val = f(arg);
console.log("called with", arg, "- got", val);
// It now returns val
return val;
};
}
So then noisy(Boolean)(0) works like this
f is the function Boolean
noisy returns a function like this
function(arg) {
var val = Boolean(arg);
return val;
}
So now we have
our returned function(0)
which executes like normal to become
function(0) {
var val = Boolean(0); // false
return val;
}
I'm relatively new to JS and I've also just been reading through Eloquent Javascript and I found it easier to understand once I understood the calling of the function (answering your point 1):
noisy(Boolean)(0);
The noisy(Boolean) creates a new function and the (0) is after it because it is being passed as an argument into that new function. If you refer back to the greater than example:
function greaterThan(n) {
return function(m) { return m > n; };
}
var greaterThan10 = greaterThan(10);
console.log(greaterThan10(11));
It could also be called in this way:
greaterThan(10)(11);
I hope that clarifies your first question about why it was called that way.
For the second question. The f in:
var val = f(arg);
is the Boolean function that was passed into noisy when noisy(Boolean) was entered. It was then used as the argument in the noisy function. I also didn't realise that Boolean could be a function in itself and not just a data type. As others have said - it converts the argument you gave it into a Boolean value and returns the result.
Therefore val becomes Boolean(arg) which becomes Boolean(0) which evaluates to false. If you try call noisy(Boolean)(1);you will see it return true. The console.log("called with", arg, "- got", val); simply logs the argument (0 in this case) and the result of evaluating it (false).
In effect, it has changed the Boolean function into one that logs the argument and result, as well as returning the result.
I hope this helps. Just writing it has helped my own understanding.
Javascript variables do not have a static datatype. They can be assigned variables of different datatypes also.
There is no concept of typecasting in JS like in JAVA etc.
() in a function call corresponds to the invoking of the function.
Here, Boolean seems to be a higher order function which is passed as a parameter to the noisy function. The result of the noisy function will be
function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
The second parantheses with 0 is used to invoke this result.
Here, within the above function, note the below line.
var val = f(arg);
Here, f corresponds to the Boolean function which was passed earlier. arg corresponds to 0.
Since val is returned, the result of the expression will be the result of Booelan(0).
In case you're still having trouble with this, here's how I understand it (it gave me a headache too..)
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0)
A function is just a regular value. The previous sentence is key to understanding what's going on here.
Our noisy(f) function is a value. It is what it returns.
noisy(f) returns a function which takes an argument (arg).
noisy(f) also takes an argument (f). Inner functions (functions called from within functions) have access to variables and arguments which were passed to the outer function.
We're calling our outer function and passing it the argument Boolean. Our outer function returns its inner function which takes an argument (0).
By understanding the above it should become clear that noisy(Boolean(0)) would simply pass an argument to our outer function,
while not passing anything to the inner function which is returned by our outer function.
It's so simple really. Now that we understand it, it's hard to believe it gave us such a headache to begin with... */`
Following code does NOT work:
function addToAnswer(param){
var answer = 10;
function adder(){
return answer + param;
};
adder();
}
console.log(addToAnswer(5)); // returns undefined, expecting 15
The fix to this code is return adder(); I feel pretty stupid that to me, addToAnswer() should return the value from adder() function. How would you answer if asked why it doesn't work?
How would you answer if asked why it doesn't work?
I'd say that in JavaScript, functions generally don't return a value unless you explicitly use return to do so. (There are languages where they do, notably CoffeeScript, but not JavaScript.)
The only exception is the concise arrow function, which implicitly returns the result of the one expression it's allowed to contain.
Here's an example of a concise arrow function being used:
someArray.sort((a, b) => a - b);
// ^^^^^^^^^^^^^^^---- concise arrow function
But that's the only exception. Verbose arrow functions, function functions, and methods all require an explicit return. If the code path taken through the function doesn't reach an explicit return with a value, the result of calling the function is the value undefined.
(Some may argue that constructor functions are a second exception to the rule, because when you do new Thingy the result is the new thingy even if Thingy doesn't have a return value, but it's not true. In that case, it's the new expression that has a result, not that the constructor is returning anything implicitly. And in fact, the distinction is clearly drawn in the specification.)
Unless a function executes a return statement, it returns undefined. It doesn't automatically return the value of the last line in the function. So when you write:
adder();
at the end of the function, it calls adder(), which returns 15. Then addToAnswer discards this value and returns undefined.
For that, you need to understand how return works.
When you call the add(); the control jumps to the start of the add function, and when inside it reaches the return statement, the control jumps back to the point where the add function was called, along with any value if processed, and continues with the rest of the code.
Since the addToAnswer function is not told to return a value, hence it processes the code( calculating param + answer), but doesn't return anything, hence the value of that function is undefined.
For the sake of experimentation you can remove the return keyword from the inner function and instead return adder();. You'd get undefined, because even though the adder function processed the code since it was not asked explicitly to return a value, it didn't.
When the function adder() returns, it only pops out the current Execution Context and return to the layer beneath it -- addToAnswer(). You need to understand how the Execution Stack works:
1. When a file is first run, a Global Execution Context is created.
2. All of the values not defined within another function are added to the Global Execution Context.
3. When the first function is run, a new execution context is created.
4. This new execution context is capable of referencing the variables and functions defined in whatever parent context is below it in the stack, in this case, the Global Execution Context.
5. Finally, a third execution context is popped onto the stack for any functions defined within function addToAnswer().
http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/
https://simpleprogrammer.com/2016/06/06/javascript-execution-stack-key-learning-language/
I am reading Eloquent JavaScript (The new edition) and I reached the part on higher order functions and I'm confused on what's happening in the following code.
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0);
// → calling with 0
// → called with 0 - got false
Why is the call to the function noisy like this? Is (Boolean) a cast? A cast for what? the return value? or the argument? why not (Boolean)noisy(0) if its the return value. Or noisy((Boolean) 0) if the argument is the one being casted.
noisy(Boolean)(0)
What is happening in this line? Where is f() even defined?
var val = f(arg);
Boolean is a function. It's the function you're calling indirectly through noisy. A bit confusing, I know, because it looks like the name of a type. But in JavaScript, those initially-capped things (Boolean, Number, String, and so on) are functions. When you call Boolean (without using new), it tries to convert the argument you gave it into a boolean primitive value and returns the result. (See §15.6.1 in the spec.)
f is the name of the argument in the noisy function.
Functions in JavaScript are first-class objects. You can pass them into other functions as arguments just like any other object.
When you do
noisy(Boolean)(0)
There are two things going on. First:
// (In effect, we're not really creating a variable...)
var x = noisy(Boolean);
That gives us a function that, when called, will call Boolean with the argument we give it while also doing those console.log statements. This is the function you see being created in noisy (return function(arg)...);
Then we call that function:
x(0);
And that's when you see the console output. Since Boolean(0) is false, you see Boolean return that value.
Here's a much simpler example:
function foo(bar) {
bar();
}
function testing() {
alert("testing got called");
}
foo(testing);
There, I'm passing the function testing into foo. The argument name I'm using for that within foo is bar. The line bar(); calls the function.
A function without the () is the actual function. A function with () is an invocation of the function. Also keep in mind that JavaScript is a loosely typed language, so you don't declare variable types. I've added some comments to your example to try and help.
// We define a function named noisy that takes in an argument named f. We are expecting f to be a function but this isn't enforced till the interpreter throws an error.
function noisy(f) {
// Noisy returns a single item, an anonymous function. That anonymous function takes in an argument named arg
return function(arg) {
console.log("calling with", arg);
// Our anonymous function then takes f (It can use f because its defined inside noisy, see closures for more details) and invokes it with the argument arg and stores the result in a variable named val.
var val = f(arg);
console.log("called with", arg, "- got", val);
// It now returns val
return val;
};
}
So then noisy(Boolean)(0) works like this
f is the function Boolean
noisy returns a function like this
function(arg) {
var val = Boolean(arg);
return val;
}
So now we have
our returned function(0)
which executes like normal to become
function(0) {
var val = Boolean(0); // false
return val;
}
I'm relatively new to JS and I've also just been reading through Eloquent Javascript and I found it easier to understand once I understood the calling of the function (answering your point 1):
noisy(Boolean)(0);
The noisy(Boolean) creates a new function and the (0) is after it because it is being passed as an argument into that new function. If you refer back to the greater than example:
function greaterThan(n) {
return function(m) { return m > n; };
}
var greaterThan10 = greaterThan(10);
console.log(greaterThan10(11));
It could also be called in this way:
greaterThan(10)(11);
I hope that clarifies your first question about why it was called that way.
For the second question. The f in:
var val = f(arg);
is the Boolean function that was passed into noisy when noisy(Boolean) was entered. It was then used as the argument in the noisy function. I also didn't realise that Boolean could be a function in itself and not just a data type. As others have said - it converts the argument you gave it into a Boolean value and returns the result.
Therefore val becomes Boolean(arg) which becomes Boolean(0) which evaluates to false. If you try call noisy(Boolean)(1);you will see it return true. The console.log("called with", arg, "- got", val); simply logs the argument (0 in this case) and the result of evaluating it (false).
In effect, it has changed the Boolean function into one that logs the argument and result, as well as returning the result.
I hope this helps. Just writing it has helped my own understanding.
Javascript variables do not have a static datatype. They can be assigned variables of different datatypes also.
There is no concept of typecasting in JS like in JAVA etc.
() in a function call corresponds to the invoking of the function.
Here, Boolean seems to be a higher order function which is passed as a parameter to the noisy function. The result of the noisy function will be
function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
The second parantheses with 0 is used to invoke this result.
Here, within the above function, note the below line.
var val = f(arg);
Here, f corresponds to the Boolean function which was passed earlier. arg corresponds to 0.
Since val is returned, the result of the expression will be the result of Booelan(0).
In case you're still having trouble with this, here's how I understand it (it gave me a headache too..)
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0)
A function is just a regular value. The previous sentence is key to understanding what's going on here.
Our noisy(f) function is a value. It is what it returns.
noisy(f) returns a function which takes an argument (arg).
noisy(f) also takes an argument (f). Inner functions (functions called from within functions) have access to variables and arguments which were passed to the outer function.
We're calling our outer function and passing it the argument Boolean. Our outer function returns its inner function which takes an argument (0).
By understanding the above it should become clear that noisy(Boolean(0)) would simply pass an argument to our outer function,
while not passing anything to the inner function which is returned by our outer function.
It's so simple really. Now that we understand it, it's hard to believe it gave us such a headache to begin with... */`
I am reading Eloquent JavaScript (The new edition) and I reached the part on higher order functions and I'm confused on what's happening in the following code.
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0);
// → calling with 0
// → called with 0 - got false
Why is the call to the function noisy like this? Is (Boolean) a cast? A cast for what? the return value? or the argument? why not (Boolean)noisy(0) if its the return value. Or noisy((Boolean) 0) if the argument is the one being casted.
noisy(Boolean)(0)
What is happening in this line? Where is f() even defined?
var val = f(arg);
Boolean is a function. It's the function you're calling indirectly through noisy. A bit confusing, I know, because it looks like the name of a type. But in JavaScript, those initially-capped things (Boolean, Number, String, and so on) are functions. When you call Boolean (without using new), it tries to convert the argument you gave it into a boolean primitive value and returns the result. (See §15.6.1 in the spec.)
f is the name of the argument in the noisy function.
Functions in JavaScript are first-class objects. You can pass them into other functions as arguments just like any other object.
When you do
noisy(Boolean)(0)
There are two things going on. First:
// (In effect, we're not really creating a variable...)
var x = noisy(Boolean);
That gives us a function that, when called, will call Boolean with the argument we give it while also doing those console.log statements. This is the function you see being created in noisy (return function(arg)...);
Then we call that function:
x(0);
And that's when you see the console output. Since Boolean(0) is false, you see Boolean return that value.
Here's a much simpler example:
function foo(bar) {
bar();
}
function testing() {
alert("testing got called");
}
foo(testing);
There, I'm passing the function testing into foo. The argument name I'm using for that within foo is bar. The line bar(); calls the function.
A function without the () is the actual function. A function with () is an invocation of the function. Also keep in mind that JavaScript is a loosely typed language, so you don't declare variable types. I've added some comments to your example to try and help.
// We define a function named noisy that takes in an argument named f. We are expecting f to be a function but this isn't enforced till the interpreter throws an error.
function noisy(f) {
// Noisy returns a single item, an anonymous function. That anonymous function takes in an argument named arg
return function(arg) {
console.log("calling with", arg);
// Our anonymous function then takes f (It can use f because its defined inside noisy, see closures for more details) and invokes it with the argument arg and stores the result in a variable named val.
var val = f(arg);
console.log("called with", arg, "- got", val);
// It now returns val
return val;
};
}
So then noisy(Boolean)(0) works like this
f is the function Boolean
noisy returns a function like this
function(arg) {
var val = Boolean(arg);
return val;
}
So now we have
our returned function(0)
which executes like normal to become
function(0) {
var val = Boolean(0); // false
return val;
}
I'm relatively new to JS and I've also just been reading through Eloquent Javascript and I found it easier to understand once I understood the calling of the function (answering your point 1):
noisy(Boolean)(0);
The noisy(Boolean) creates a new function and the (0) is after it because it is being passed as an argument into that new function. If you refer back to the greater than example:
function greaterThan(n) {
return function(m) { return m > n; };
}
var greaterThan10 = greaterThan(10);
console.log(greaterThan10(11));
It could also be called in this way:
greaterThan(10)(11);
I hope that clarifies your first question about why it was called that way.
For the second question. The f in:
var val = f(arg);
is the Boolean function that was passed into noisy when noisy(Boolean) was entered. It was then used as the argument in the noisy function. I also didn't realise that Boolean could be a function in itself and not just a data type. As others have said - it converts the argument you gave it into a Boolean value and returns the result.
Therefore val becomes Boolean(arg) which becomes Boolean(0) which evaluates to false. If you try call noisy(Boolean)(1);you will see it return true. The console.log("called with", arg, "- got", val); simply logs the argument (0 in this case) and the result of evaluating it (false).
In effect, it has changed the Boolean function into one that logs the argument and result, as well as returning the result.
I hope this helps. Just writing it has helped my own understanding.
Javascript variables do not have a static datatype. They can be assigned variables of different datatypes also.
There is no concept of typecasting in JS like in JAVA etc.
() in a function call corresponds to the invoking of the function.
Here, Boolean seems to be a higher order function which is passed as a parameter to the noisy function. The result of the noisy function will be
function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
The second parantheses with 0 is used to invoke this result.
Here, within the above function, note the below line.
var val = f(arg);
Here, f corresponds to the Boolean function which was passed earlier. arg corresponds to 0.
Since val is returned, the result of the expression will be the result of Booelan(0).
In case you're still having trouble with this, here's how I understand it (it gave me a headache too..)
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0)
A function is just a regular value. The previous sentence is key to understanding what's going on here.
Our noisy(f) function is a value. It is what it returns.
noisy(f) returns a function which takes an argument (arg).
noisy(f) also takes an argument (f). Inner functions (functions called from within functions) have access to variables and arguments which were passed to the outer function.
We're calling our outer function and passing it the argument Boolean. Our outer function returns its inner function which takes an argument (0).
By understanding the above it should become clear that noisy(Boolean(0)) would simply pass an argument to our outer function,
while not passing anything to the inner function which is returned by our outer function.
It's so simple really. Now that we understand it, it's hard to believe it gave us such a headache to begin with... */`
As a new javascript developer, I have spent some time with this code snippit from Chapter 6 of Eloquent Javascript, I am still trying to understand the following code example :
function negate(func) {
return function(x) {
return !func(x);
};
}
var isNotNaN = negate(isNaN);
document.writeln(isNotNaN(NaN));
Where it particular loses me is the following line, I just don't understand the call in general and where the variable/value for NaN comes from:
document.writeln(isNotNaN(NaN));
I think xdazz pretty much covered it, but since you said you still don't get it maybe it would help to hear the explanation in somebody else's words.
This line:
var isNotNaN = negate(isNaN);
...declares a variable isNotNan that is assigned equal to the result of a call to the negate() function, passing isNan as a parameter.
That parameter isNan is actually a function as described by MDN, but negate() would accept any function as a parameter, you could say for example var isNotFinite = negate(isFinite);.
Now the negate() function actually creates and returns another function, so after that line runs isNotNan references that returned function, which means you can call it as isNotNan(someVal).
So then the line:
document.writeln(isNotNaN(NaN));
... calls isNotNan() and passes it NaN as a parameter, and the result is written out to the document.
"I just don't understand...where the variable/value for NaN comes from"
NaN is a property of the global object. To oversimplify, it is a constant provided to you by the JS environment.
Regarding how the negate() function works, it relies on the concept of "closures", which means that functions declared inside negate() have access to its variables and parameters even after negate() completes. You'll notice that the returned function references the func parameter. So when you call the returned function via isNotNaN() it can still access that original func parameter that is set to the isNan function.
The effect is kind of like doing this:
var isNotNaN = function(x) {
return !isNan(x);
};
negate take a function as parameter, and returns a new function which returns the opposite result of the original function.
NaN is A value representing Not-A-Number.
NaN is a property of the global object.
The initial value of NaN is Not-A-Number — the same as the value of
Number.NaN. In modern browsers, NaN is a non-configurable,
non-writable property. Even when this is not the case, avoid
overriding it.
NaN is a property of the global object, So it is window.NaN.
And note typeof NaN returns number.