I'm learning Java Script at the moment via a course on Udemy, and I stumbled something I found peculiar.
It is about "callback functions" and the implementation in the course uses anonymous functions.
For example
var button = document.querySelector("button");
button.addEventListener("click", function() { console.log("hi"); } );
document.addEventListener("keydown", function(event) { console.log(event); } );
In the second line, the callback function is an anonymous function with no input parameters. In the third line, the anonymous function has one input parameter: event.
I feel like we are assuming that the callback can handle 0 or 1 input parameters, but how can we know for certain? What if I define an anonymous function with 3 input parameters? Would it matter?
Both lines will work, so I'm really surprised in the flexibility of the callback function.
It's not a feature of callback parameters. It's how functions behave in general in javascript.
A function defined with one parameter can be called with either zero, one or more than one parameter in javascript without any syntax errors:
function testing (a) {
console.log(a);
}
testing(); // will log undefined
testing('hello'); // logs "hello"
testing('hello', 'world'); // logs "hello"
This means:
A function with zero parameters may be called with any number of arguments
A function with many parameters may be called with no arguments
DOM events will always call your function with one argument (except on older versions of IE which will call them with zero arguments):
your_callback(event);
As such, you are free to define your callback with an argument if you plan to use it or omit the argument if you want to ignore it.
Related
I have the following code:
$(document).ready(funcA);
function funcA(){
funcB();
}
function funcB(){
//some code
}
On the funcB, I want to know if it was called by the $(document).ready event or not.
It is any way I can do this?
Don't do this
arguments.caller gives you the function that made the call.
You can compare it to a function, like so
if(arguments.caller == funcA)
since functions are types of variables. You can then do a loop that takes the arguments.caller of the arguments.caller and trace the route until you get null.
However, this is a non-standard feature and likely will not work
Instead
You might want to re-write all your functions so that they pass on a message to the funcB function, like this
What I mean is that you do this (or something with the same principle)
$(document).ready(function(){funcA("called by event listener")});
funcA(message){
funcB(message);
}
funcB(message){
if(message == "called by event listener") alert("Came from event listener");
}
Note that you do not have to name the arguments (in case you do not want to clutter everything), if you use arguments[arguments.length - 1]. arguments is an array of all arguments.
You could also try and mess around with the Function prototype, and try to make every function call pass along the last argument that it received, so that you do not have to do it yourself.
I have an event handler which (a) requires parameters, and (b) calls a callback function via window.setTimeout. I use bind to attach the event handler.
The called function is called with additional parameters. I have tried both callback(parameters) and `callback.call(this,parameters).
Below is a code sample:
var element=document.querySelector('h1');
element.onclick=function(e) {
delay(test.bind(element,'from original','also from original',e));
}
function test(a,b,c,d,e) {
alert(this); // element
alert(a); // from original
alert(b); // also from original
alert(c); // event
alert(d); // from delayed
alert(e); // also from delayed
}
function delay(callback) {
window.setTimeout(delayed,100);
function delayed() {
// callback.call(this,'from delayed','also from delayed');
callback('from delayed','also from delayed');
}
}
I my testing, I find that callback gets the parameters in the following order:
Parameters from the original function
The event itself
Parameters from the function calling the callback
Further, I find that the callback function has this set to the original element, even if I call it using .call with the this argument set to anything (even null).
I can handle this certainty, but I am confused as to how this is formally handled. I can’t find anything in the documentation which discusses an event listener with a callback.
The question is:
Where is the ordering of the parameters documented?
Where does this come from, and why does it seem to ignore any attempts to change ie?
Thanks
As you can see by the bind() documentation:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
So this line: test.bind(element,'from original','also from original',e)
will return a function that when called will use those provided arguments first, and any subsequent arguments after those. So when calling your function, it will result in the order you list above.
As for this, the problem is that you are using setTimeout() after the bind, which is why you might not be getting what you are expecting. You can read more about setTimeout() and this here.
I've been a Javascript tinkerer for quite some time and recently I have been trying to have a real good understanding of the code I write. I want to get really good at writing Javascript. One of the things that's confused me a little bit was the usage of callback functions. I've just avoided using callbacks up until now. Right now, I'd like to know if my understanding of how a basic callback works is accurate and also if my understanding of parameters and arguments is accurate and finally, what the purpose is of using the callback in this scenario. Is there a benefit to using the callback function I've created below? If not, when are callback functions most beneficial? I realize what I've written below is quite lengthy so for the TLDR people: Am I right in thinking It's as if I created the function "theCallback" within "myFunction"? If so, what is the benefit in the scenario below? Why not just call a function? why must the function being called be an argument in the "myFunction" function?
If the scenario below doesn't make it necessary for using a callback, when is it necessary and what are the benefits? Thanks.
Here's how I see the code below: I've created a factory function "myFunction" with two parameters "x" and "callback" and parameters are pretty much variables that will be stored with arguments when the function is called. I also created another factory function "theCallback" with two parameters "x" and "theValue". Now since these are factory functions, regardless of them being underneath a function call to "myFunction", they will be hoisted above the function call so there are no problems. Had I created a function expression with a variable, they would not be hoisted. So now my call to "myFunction" has two arguments that the parameters in it will be defined as, "3" and "theCallback". The "theCallback" argument is a function. This function has the two parameters "x" and "theValue". When "myFunction" is called, "x" is stored with the argument "3" and "callback" is stored with the function "theCallback" and then the code within "myFunction" is executed which is simply a variable declared and assigned a value of a string that contains the text "for the callback" and the callback variable (I'm viewing as a variable), which was a parameter that is now an argument which is "theCallback" function I created which also contains parameters itself, is called, and given arguments for it's code to execute. In this case, the code it will execute calls the built in alert function (or method of the window object?) and gives the alert function a string argument, followed by the
alert function called again with the argument of "x" which is stored with "3" and then again alert is called and given the argument of "theValue" which contains the string "for the callback". Now when "theCallback" function is passed as a second argument to "myFunction" and it's stored in "callback", It's as if I created the function "theCallback" within "myFunction" right? If so, what is the benefit in the scenario below? Why not just call a function, why must the function being called be an argument in the "myFunction" function?
If the scenario below doesn't make it necessary for using a callback, when is it necessary and what are the benefits?
myFunction(3, theCallback);
function myFunction(x, callback){
var value = 'for the callback';
callback(x, value);
}
function theCallback(x, theValue){
alert('this is the callback function');
alert(x);
alert(theValue);
}
Is there a benefit to using the callback function I've created below?
That's a little subjective. Using a callback is unnecessary there. Normally you would return data from one function and pass it to the other.
when are callback functions most beneficial?
When you need to deal with the data after an event has fired, instead of immediately. e.g. when a button is clicked or an HTTP response has fired.
myButton.addEventListener("click", myCallbackFunction);
I've created a factory function "myFunction"
No. That is just a function. Factory functions create class objects.
they will be hoisted
Function declarations (as opposed to function expressions) are hoisted. This isn't relevant to callbacks though. A callback is basically a function passed as an argument, it doesn't matter how it was created.
what are the benefits
The benefits are that you can have different things happen when the event fires depending on the circumstance.
Take the click event example above. Often you'll want clicking on different things to have different effects, not the one thing that addEventListener was hardcoded to make happen by the browser vendor.
I've just come across this little snippet of JavaScript code online:
exampleSocket.onopen = function(event) { // rest of code here;}
And I'm rather confused about the function(event) part, as there are no comments for me to analyze. (Who needs comments when you're designing bi-directional duplex connections? Haha ).
What exactly is function(event)? I always thought you had to define a function name with the function in javaScript. Is this an example of bad code? Additionally, the (argument-parameter-whatever) 'event' isn't even defined anywhere else in the code. Just bam. There it is. Is it necessary to define that, or is (event) a special predefined value? Lastly, if you were to replace (event) with some other value like (e), would the code still work?
Thanks
What you've got there is a function expression, not a function statement.
In a function statement, the name is mandatory. In a function expression it is optional. A function expression with a name is called a named function expression. A function expression without is called an anonymous function
There are a number of subtle differences between all these different methods of declaring a function which are covered in this question; var functionName = function() {} vs function functionName() {}
What you're doing here is setting the onopen property of exampleSocket to a function (expression). Note that you are not running that function at all; you are simply declaring it, and saving a reference to it in exampleSocket.onopen.
This means that someone can execute that function when they want to by calling;
exampleSocket.open();
They can pass a parameter to the function, which you can use inside the function using the event variable (and to answer your question; event is not a special word. You can call it anything).
exampleSocket.onopen = function (event) {
console.log(event); // will log "hello"
};
exampleSocket.open("hello");
The fact the variable event isn't used anywhere will likely mean the developer has named the argument to say "hey, look, you can use this if you want to", but hasn't in his actual implementation.
You don't have to declare the variable yourself. It is declared already by being named in the argument list, and it will be initialized to a value when someone passes an argument when they call the function.
Note that we could define this event handler using a function statement;
function foo(event) {
console.log(event);
}
exampleSocket.open = foo;
... or via a named function expression:
exampleSocket.open = function foo(event) {
console.log(event);
};
To confuse things (don't worry about this; it's a quirk of JavaScript) the name of a named function expression is only available inside the function itself;
exampleSocket.open = function foo(event) {
console.log(event);
console.log(typeof foo); // you'll get "function"
};
console.log(typeof foo); // you'll get "undefined"
... but in a function statement, you'll be able to access the name both inside and out.
I hope this helps... it's a bit of a "brain dump" of information :).
This is an anonymous function. A function is a value, and you can declare and store functions like this. More information on that syntax in this question.
Reading the code (I don't think it needs any more comments than it already has), you are writing a handler function which is called when the socket opens. The socket open event will be passed to the function in the variable event.
Why event? Because the API, whatever it is, expects to pass in an argument that represents the 'open' event.
It's a simple and common JS event-binding function.
It attach an anonymous function to the "open" event of "exampleSocket".
When such event is fired the declared function is called.
Each event may have some parameters, which contain additional info about the event itself.
You can name that parameter the way you want ("event","e" or "anythingElse") and then you can refer to it in the anonymous function body.
You are basically assigning a function value to exampleSocket.onopen, which can then be called elsewhere. Imagine something like this:
var obj = {};
obj.onsomething = function(a, b, c, d) {
alert(a+b+c+d);
};
obj.onsomething(1, 2, 3, 4);
In this case, I gave obj.onsomething a function that takes 4 parameters (should be numbers) and alerts the sum. Then I can just call obj.onsomething with 4 parameters.
So the function that you assign to exampleSocket.onopen will get called when it is appropriate (for example, when the socket is open).
Hope that helps.
Now, I usually call a function (that requires no arguments) with () like this:
myFunction(); //there's empty parens
Except in jQuery calls where I can get away with:
$('#foo').bind('click', myFunction); //no parens
Fine. But recently I saw this comment here on SO:
"Consider using setTimeout(monitor, 100); instead of setTimeout('monitor()', 100);. Eval is evil :)"
Yikes! Are we really eval()-ing a string here? I guess I don't really understand the significance and implications of 'calling' a function. What are the real rules about calling and referring to functions?
In JavaScript functions are first-class objects. That means you can pass functions around as parameters to a function, or treat them as variables in general.
Let's say we are talking about a function hello,
function hello() {
alert('yo');
}
When we simply write
hello
we are referring to the function which doesn't execute it's contents. But when we add the parens () after the function name,
hello()
then we are actually calling the function which will alert "yo" on the screen.
The bind method in jQuery accepts the type of event (string) and a function as its arguments. In your example, you are passing the type - "click" and the actual function as an argument.
Have you seen Inception? Consider this contrived example which might make things clearer. Since functions are first-class objects in JavaScript, we can pass and return a function from within a function. So let's create a function that returns a function when invoked, and the returned function also returns another function when invoked.
function reality() {
return function() {
return function() {
alert('in a Limbo');
}
};
}
Here reality is a function, reality() is a function, and reality()() is a function as well. However reality()()() is not a function, but simply undefined as we are not returning a function (we aren't returning anything) from the innermost function.
So for the reality function example, you could have passed any of the following to jQuery's bind.
$('#foo').bind('click', reality);
$('#foo').bind('click', reality());
$('#foo').bind('click', reality()());
Your jQuery bind example is similar to setTimeout(monitor, 100);, you are passing a reference of a function object as an argument.
Passing a string to the setTimeout/setInterval methods should be avoided for the same reasons you should avoid eval and the Function constructor when it is unnecessary.
The code passed as a string will be evaluated and run in the global execution context, which can give you "scope issues", consider the following example:
// a global function
var f = function () {
alert('global');
};
(function () {
// a local function
var f = function() {
alert('local');
};
setTimeout('f()', 100); // will alert "global"
setTimeout(f, 100); // will alert "local"
})();
The first setTimeout call in the above example, will execute the global f function, because the evaluated code has no access to the local lexical scope of the anonymous function.
If you pass the reference of a function object to the setTimeout method -like in the second setTimeout call- the exact same function you refer in the current scope will be executed.
You are not doing the same thing in your jQuery example as in the second setTimeout example - in your code you are passing the function and binding the click event.
In the first setTimout example, the monitor function is passed in and can be invoked directly, in the second, the sting monitor() is passed in and needs to be evaled.
When passing a function around, you use the function name. When invoking it, you need to use the ().
Eval will invoke what is passed in, so a () is required for a successful function invocation.
First of all, "()" is not part of the function name.
It is syntax used to make function calls.
First, you bind a function to an identifier name by either using a function declaration:
function x() {
return "blah";
}
... or by using a function expression:
var x = function() {
return "blah";
};
Now, whenever you want to run this function, you use the parens:
x();
The setTimeout function accepts both and identifier to a function, or a string as the first argument...
setTimeout(x, 1000);
setTimeout("x()", 1000);
If you supply an identifier, then it will get called as a function.
If you supply an string, than it will be evaluated (executed).
The first method (supplying an identifier) is preferred ...