This conversation came up at work today and I wasn't completely able to grasp the difference, and my google search so far has been fruitless.
The example that was used at work was the difference between
DoSomethingFunction().then(function(){
DoSomethingElse();
});
and
DoSomethingFunction().then(DoSomethingElse());
To me, I look at the first, and it's an anonymous function, so that would just get called and inside it, is the function we want to call, but that's why I used the second version, which just calls the function without wrapping it in a separate function.
Can somebody explain the difference to me?
Functions in JavaScript are objects, and can be passed around just like any other object. DoSomethingElse is a function object that can be executed with DoSomethingElse().
.then expects a function object, so the following just executes the function and returns its value or undefined if it returns nothing:
// this is wrong, unless `DoSomethingElse` returns a function
DoSomethingFunction().then(DoSomethingElse());
The following passes an anonymous function (this is what .then expects, a function), then executes DoSomethingElse inside.
DoSomethingFunction().then(function(){
DoSomethingElse();
});
The following passes the function object to then, and does the same as the above:
DoSomethingFunction().then(DoSomethingElse);
Passing a function means, that a function is passed as an argument, and it can be called in the called function. Calling a function means that the function body is executed, and it returns a value. In your example
DoSomethingFunction().then(DoSomethingElse());
you pass the result of a function call, so the result of calling DoSomethingElse (the return value).
In case of
DoSomethingFunction().then(DoSomethingElse);
you pass a function, which then needs to be executed in the then function to get it's result.
Related
I'm following a tutorial by Tyler McGinnis on execution contexts, call stacks and closures.
https://www.youtube.com/watch?v=Nt-qa_LlUH0&feature=emb_title
I'm a bit confused with the closure example. I understand a closure is when a function is inside another function. I also understand that the inner function has access to the parent functions arguments (As explained in the video).
My confusion is in the code below is when makeAdder(5) is invoked is the inner function not invoked aswell on the first invokation? Tyler appears to suggest makeAdder is popped off the call stack when first invoked just leaving the inner function untouched.
The second part I don't understand when we call add5(2) this is invoking makeAdder(5) no? How do we add 2 arguments when the parent function only accepts one?
If someone could walk it through step by step of how it's all invoked that would be great!
var count = 0;
function makeAdder(x) {
return function inner(y) {
return x + y;
}
}
var add5 = makeAdder(5);
console.log(add5); // what the call to makeAdder returns
count += add5(2);
console.log(count);
when makeAdder(5) is invoked, is the inner function not invoked as well on the first invocation?
No, it isn't. Only makeAdder is invoked at that time, and makeAdder is not making any calls itself. It merely returns an object, and that object happens to be a function. And returning a function is done without actually invoking it.
when we call add5(2) this is invoking makeAdder(5) no?
It is not invoking makeAdder(5). Earlier on add5 was the result of calling makeAdder(5), and so add5 is that inner function. The special thing happening here is that when you call add5, an "execution context" is restored, which represents the state of affairs inside makeAdder at the moment it returned the function. This practically means that when add5 (the inner function) references the x variable, it will find the value in x it had at the moment makeAdder had been called earlier on.
How do we add 2 arguments when the parent function only accepts one?
Indeed, when we call the parent function, the second argument is not known yet, and we don't need to know it at that moment, since the inner function is not yet executed at that moment. The important thing with the call of the parent function, is that we establish the value of x, which will "live on", even though it can only be accessed by calling the inner function.
And when we call the inner function, we provide the second argument that is needed. The inner function can then combine the "magical" reference it has to the x value (provided when we made the parent call), with the normal argument it receives itself.
A simple way to look at this is as a function that returns a function--which can be called like a normal function because it is. So the first call of the function return type is a function.
Look the following example
function add(x,y){
return x+y;
}
function subtract(x,y) {
return x-y;
}
function calculator(type){
if(type ==='add'){
return add ; //here we are returning a function - the above add function
}
if (type==='subtract')
{
return subtract; // we are returning a function - the above subtract function
}
return null;
}
var fn = calculator('add'); // this call will return the function add which can be called as in below
var result = fn(4,5);
console.log(result) ; ///should print 9
Likewise the first call
var add5 = makeAdder(5);
returns a function which is exactly
function inner(y) { return x+5);
Then you can call add5(2) which essentially execute the above function.
Why there is no parentheses for console.log inside of then block of promise?
How does it know that what should it log?
const Category = require('./models/category');
const cat = Category.find({}).then(console.log);
It's passing a function reference as a callback. console.log refers to a function to be called when the promise resolves as opposed to actually calling console.log.
Functions are first-class objects in JavaScript. They can be passed around. Just like you would do then(x => console.log(x)). If you call it before-hand, it will be necessarily evaluated before (and its return value passed):
promise.then(console.log()) // Called immediately, undefined passed to then
Note that it's not exactly the same as then(x => console.log(x)). Any context is lost because the callee has no way to recover that from just a function reference. Though this doesn't have an effect here AFAIK.
This is a reference to the function that will be called after Category.find(). The value passed to it will be the result of the find.
Calling console.log() inside the then callback would output nothing in the console. Usually, you pass an anonymous or arrow function to the callback argument, but since console.log can pretty much have anything as a parameter, you just have to pass the name of the function so the Promise can execute it later.
I am new learner of Javascript and I got stuck in "functions returned from other functions".
The code is as below.
var createScream = function(logger) { return function(message) {
logger(message.toUpperCase() + "!!!")
}
}
const scream = createScream(message => console.log(message))
scream('functions can be returned from other functions')
scream('createScream returns a function')
scream('scream invokes that returned function')
Console output:
"FUNCTIONS CAN BE RETURNED FROM OTHER FUNCTIONS!!!" "CREATESCREAM
RETURNS A FUNCTION!!!" "SCREAM INVOKES THAT RETURNED FUNCTION!!!"
Question: why it will work this way? what is the process of executing?
Does function scream have any parameter? how does it work?
This may be very easy, I searched but no clear explanation.
Can someone please give me a hint or explain the whole execution process in details?
Thanks in advance!
First, Higher order functions are not about functional languages. Functions that operate on other functions i.e. taking a function as an argument and returning another function, are called higher order functions.
Your snippet:
You created an anonymous function with argument logger, which returns another anonymous function and bind that to variable createScream.
Then you called createScream with a function as an argument. storing the returned value in const scream. At this time you are returned a function with argument logger being the fat arrow function you passed.
Now you called scream with strings. Remember scream is also a function because in the earlier step the function call returned another function. That function has access to logger argument passed to the outer function. This is an example of closure.
When you call scream with strings. The returned function is called which is logging the message in uppercase plus !!!.
It will take sometime to get what is happening here, If you have limited programming experience. Read about higher order functions, lexical scope, closure.
In JavaScript and other functional languages, you will hear the term that functions are "first-class citizens" meaning that functions can be passed around as values or referenced by other functions.
It's normal for this to take a bit of time to grok, but try to walk through your code step by step and you'll get it:
The createScream function accepts a function as input (logger)
The createScream function then returns another function that accepts its own input (message)
The returned function uses the original input function (logger) as well as the second input (message)
And consider the execution order in usage as well:
scream invokes createScream with a console.log function
now when you invoke scream with a message, that message will first be changed as per the definition in createScream
then once the message is changed, it is invoked by the logger function console.log
I'm very new to js so I'd appreciate some help. I have two blocks of code that I think should work identically but don't. Can someone explain how they're different? It looks like in the first piece of code, the parser enters the function directly.
function embedGameSwfAfterReg() {
embedGameSwf("{$swfLocation}", "100%", "100%", {$flashVars});
}
API.registerOnload(embedGameSwfAfterReg())
and
API.registerOnload(function() {
embedGameSwfAfterReg("{$swfLocation}", "100%", "100%", {$flashVars});
});
In the first code block, you're registering the result of the embedGameSwfAfterReg function (undefined) as the onload function (() means you're evaluating the function). Remove the parentheses to have the embedGameSwfAfterReg function itself registered:
API.registerOnload(embedGameSwfAfterReg)
This
API.registerOnload(embedGameSwfAfterReg())
runs embedGameSwfAfterReg, and then passes the return value (undefined since it doesn't return a value), to registerOnLoad
you want
API.registerOnload(embedGameSwfAfterReg)
which passes the function itself to registerOnload
Functions are objects in Javascript and can be passed directly by their names. When you add the parens, it instead runs the function and passes the result.
function embedGameSwfAfterReg() {
embedGameSwf("{$swfLocation}", "100%", "100%", {$flashVars});
}
API.registerOnload(embedGameSwfAfterReg)
and
API.registerOnload(function() {
embedGameSwfAfterReg("{$swfLocation}", "100%", "100%", {$flashVars});
});
would work the same way.
The difference is () which you have put with embedGameSwfAfterReg function in the first case
It actually calls the function there only but its different in the 2nd case.
I'm asssuming that the second example should be
API.registerOnload(function() {
embedGameSwf("{$swfLocation}", "100%", "100%", {$flashVars});
});
If so, then the difference is quite big. In the first case, the embedGameSwfAfterReg function is invoked and the embedGameSwf is called when you register. This is probably not what you want since the the return value of the function is undefined.
In the second case, the anonymous function is not invoked until later when the registerOnLoad event is raised. This is probably what you want.
API.registerOnload() takes a callback function as parameter, therefore you only have to pass in the function name as reference, otherwise the function is directly getting called when the code runs.
// Correct form is:
API.registerOnload(embedGameSWFAfterReg)
Your second sample already is an anonymous function that is handled like an function callback and therefore evaluated when API.registerOnload(callback) is calling the reference with callback() somewhere inside it's code.
Short answer:
First piece of code do nothing, because embedGameSwfAfterReg doesn't have a return statement. Probably it could even end up with an error if API.registerOnload doesn't accurately check its arguments before execution.
Second piece of code creates an anonymous-function that is passed as an argument to API.registerOnload method which (as far as I can see from method name) runs functions during an Onload event.
Long answer:
In the first piece of code you declare a new function named embedGameSwfAfterReg which resists in global-scope of your code:
function embedGameSwfAfterReg() {
// calls embedGameSwf function
}
after, you execute defined function and pass the result to registerOnload method of an object named API:
API.registerOnload(embedGameSwfAfterReg());
As you probably mentioned, declared function embedGameSwfAfterReg has no return statement, so the result of its execution will be undefined. In other words
API.registerOnload(embedGameSwfAfterReg());
is doing the same as
embedGameSwfAfterReg();
API.registerOnload();
so eventually it calls API.registerOnload() WITHOUT any arguments passed!
Second piece of code creates an anonymous function (functions are specific objects in JS, which can be passed to other functions/methods, have its own methods and executed). Then it passes created function (or better say a reference to the function) to registerOnload - method of an object called "API".
You should read topics about Objects, Function-type, scopes, anonymous functions and closures in JS. I would advise Mozilla JavaScript guide
Also feels free to play with a simplified example at jsfiddle which gives some practical hint on anonymous functions in JS.
I want to periodically query a PHP script for new messages. To do so, I'm using the setInterval() function and AJAX.
$(document).ready(function(){
var queryInterval = 1000; /* How fast we query for new messages */
setInterval(getMessages(), queryInterval);
function getMessages() {
console.log("tick");
}
});
However, when I look at the Javascript console, I'm only seeing "tick" once. I've made sure that the console doesn't ignore any more logs of the same strings, so if the code was working properly it should show "tick" in the console every second.
Anyone know what could be going wrong here?
Change:
setInterval(getMessages(), queryInterval);
To:
setInterval(getMessages, queryInterval);
Actually, setInterval isn't running getMessages at all (not even once). setInterval expects a reference to a function, but you're executing the getMessages function immediately and passing its return value to setInterval (which is undefined). That's what the parens after getMessage do.
Pass a reference to setInterval like this:
setInterval(getMessages, queryInterval);
If this is the only place that getMessages is used, then you could also write it like this:
setInterval(function() {
console.log("tick");
}, queryInterval);
Remove the () after getMessage
This calls getMessages, not schedules it. Remove the parenthesis.
setInterval(getMessages(), queryInterval);
setInterval(getMessages, queryInterval);
Although others have already covered this ground above, both window.setTimeout() and window.setInterval() require function references. Your code provides, instead, the return value from a function invocation.
When you wish to call, or invoke, a JavaScript function, you write, as expected:
DoMyfunction();
The JavaScript engine will execute that function upon encountering that line.
However, what setTimeout() and setInterval() require, is a reference to the function object corresponding to your function. Which you obtain via the following, and similar means:
myFunc = DoMyFunction;
That line copies a reference to the function object corresponding to DoMyFunction() into a new variable. Which you can then pass to setInterval() and setTimeout(), viz:
discard = window.setTimeout(myFunc, 1000);
That line above will direct the JavaScript engine to execute your intended function (namely DoMyFunction()) once, after 1 second has elapsed, and:
discard = window.setInterval(myFunc, 1000);
will direct the JavaScript engine to execute your intended function repeatedly, once every second.
You could, of course, achieve the same effect, without using a new variable, simply as follows:
discard = window.setTimeout(DoMyFunction, 1000);
etc.
If, however, you make the mistake of using:
discard = window.setTimeout(DoMyFunction(), 1000);
what happens instead is that DoMyFunction() is executed, and any return parameter arising therefrom is then passed to the window.setTimeout() function. Since window.setTimeout() is expecting a function object reference to be passed here, and instead receives whatever your function returns (or undefined if your function returns nothing), then the internal checking performed by setTimeout() (and setInterval()) will reveal that it hasn't received a function object reference here, and simply abort silently.
A far more insidious bug, of course, could arise if DoMyFunction() actually does return a valid function object! If you've written DoMyFunction() to do this, then that function object will be passed to setTimeout() instead, and that function will be run! Of course, you could use this intentionally, and write your DoMyFunction() as a closure, returning the actual function you want setTimeout() to execute as a function object return parameter, and if you use that approach, then the form:
discard = window.setTimeout(DoMyFunction(), 1000);
will no longer be erroneous.
Remember, every JavaScript function you write in your code, when that code is parsed, is associated with a function object by the JavaScript engine. To execute the function, use:
DoMyFunction();
To reference the function object instead, use:
DoMyFunction;
Those () can make a huge amount of difference according to context, as a result of JavaScript taking this approach to differentiating between a function object reference and a function execution instruction.
Check your code line:
setInterval(getMessages(), queryInterval);
The setInterval function requires you to pass the reference to your callback function.
When you pass getMessages(), You are actually calling the function and passing its returning object to the setInterval function.
So just change your line to:
setInterval(getMessages, queryInterval);
and it will works fine!