Calling jQuery event handler on click : anonymous vs named function behaviour - javascript

Playing around with the .on('click', ) event and I get differing behaviour based on whether I supply an anonymous vs named function (the named function doesn't work). Is this a syntax error?
<div id="myID"> abc </div>
<script>
$("#myID").on('click',function(e){
console.log(e.type);
}); //works
function handle(e){
console.log(e.type);
}
$("#myID").on('click',handle(e)); //doesn't work
</script>

You need to replace
$("#myID").on('click',handle(e));
with
$("#myID").on('click',handle);

When you call a function, it is executed immediately. This happens when you do
$("#myID").on('click',handle(e));
You call the function, passing an event e which does not exist yet. What you want instead is giving jQuery a function that it should call when the user clicks on the element with the id myID.
This is possible in JavaScript because it has first-class functions. This means that if you create a function like this:
function handle(e){
console.log(e.type);
}
then you get a reference to the function that you just created. This reference is stored in a variable named handle. You could achieve the same if you do:
var handle = function (e) { // create a function and store a reference to it in a variable
console.log(e.type);
};
The function takes an argument e. This doesn't exist yet, it has to exist in the moment you call the function:
handle(e); // ReferenceError: e is not defined
You can pass the reference to that function to jQuery, which then calls your function when the user clicks the element. At that point, e still doesn't exist, because it will contain information about the event, which hasn't occured yet. It will look like this:
$("#myID").on('click', handle); // pass a reference to the handle function to jQuery
Now, handle doesn't get called, because you only pass a reference to the function. You could say that you pass the function as an argument to another (jQuery) function. This is called a callback function.
Edit
Note that all functions that were created above take e as their argument. The argument doesn't have to exist in the very moment you create the function. However, when you (or jQuery) call the function, you have to provide an argument so that the function can do its job.
It's the same with an unnamed function: you create the function, but the argument does not exist yet. When you (or jQuery) call the function, you have to provide an argument.
This means there is no essential difference. The only difference is that one function has a name, the other one doesn't. You could even do this:
$("#myID").on('click', function handle (e) { // pass a reference to the function, but do not call it
console.log(e.type);
});
... which has the same effect as:
$("#myID").on('click', function (e) { // pass a reference to the function, but do not call it
console.log(e.type);
});
... except that in the first example, you keep a reference to the function that you created in a variable called "handle". In the second example, you lose the reference to the function, and only jQuery will be able to use your function.
Edit end
Another example for that would be:
var testFunction = function (arg) {
console.log('My argument is:', arg);
};
var executeTwoTimes = function (callback) { // accept a callback function as the first argument
callback('foo'); // execute the callback function
callback('foo');
};
executeTwoTimes(testFunction); // pass a reference to testFunction
// or:
executeTwoTimes(function (a) { // pass a reference to an anonymous function
console.log(a + ' bar');
});
I hope I could make things clearer for you.

Related

Can someone explain this piece of Javascript code?

Sorry for the ambiguous title, I just didn't know what else to put. Im learning JS and in the video the person does this.
When he calls the addListAfterKeyPress method at the bottom, why does the function call work? I thought he would have to put in a argument for the addListAfterKeyPress to take in since it has an event parameter. But in the end the code works perfectly. And also, when can i call a function that takes a parameter without explicitly passing one like how he did it in the picture?
This is a so called callback.
addListAfterKeypress at line 30 is not a call to this function, it is just saying, whenever the event keypress is raised on this input element, call this function.
Who is calling the function is the DOM library, indeed. You just have to pass a pointer to the function to be called.
Even more, the addListAfterKeypress function expects an event parameter, which will be provided to the function by the DOM library.
I think it is a bit more understanding by looking at an annonymous function there.
input.addEventListener('keypress', event => {
// This will be run whenever the input raises an event of type 'keypress'
// Here, the DOM library provides me an event parameter
});
Edit on demand:
Be aware, I am using ES6 just for comfort.
Suppose having this function
const callback = () => {
console.log(`My callback function is being executed`);
};
I will be using setTimeout to mock the HTML events. setTimeout is a function that expects a callback to execute after n milliseconds.The first parameter is the callback itself, the second is the amount of milliseconds, n.
See https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout(callback, 500); // After 500ms, function callback will be fired
Here, I am just passing a pointer to the setTimeout function. This pointer must point to a function that will be called by setTimeout.
Let's write our own function that takes a callback as a parameter.
const callback2 = (number) => {
console.log('I received this parameter', number);
};
const callbackWrap = (callback, n) => {
// Here, callback parameter is a function that I can invoke, actually
console.log('The wrapper will execute the function passed as parameter');
callback(n);
};
Now, we can call the wrapper pointing to the new callback (callback2).
callbackWrap(callback2, 3);
callbackWrap(callback2, 4);
Or, we can define our function directly on the parameter list.
That is, we are passing an annonymous function
// p is the parameter of the callback function
callbackWrap(p => {
// Since callbackWrap will call the function parameter
// by passing a single parameter,
// the function I am declaring, expects that parameter
console.log(`Received ${p} inside the annonymous function`);
}, 'Parameter');
So, to summerize a bit, just the same way you can declare a variable (let's say, of type number) and then pass it to a function as a parameter, you can declare a function to pass it the same way.
const normalParameter = 30;
const functionParameter = p => console.log('Another callback', p);
callbackWrap(functionParameter, normalParameter);
// Or maybe passing more complex parameters
const anotherParameter = [1, '2', {3: 4}];
callbackWrap(functionParameter, anotherParameter );
Hope it clarifies a bit.

Why wrap a function reference into an anonymous function can correct 'this' point to?

Why wrap a function reference into an anonymous function can correct 'this' point to?
var logger = {
x: 0,
updateCount: function () {
this.x++;
console.log( this.x );
console.log( "Now I'm pointing to : " + this );
}
}
when I call like this
btn.addEventListener('click', logger.updateCount );
// may work like below
function cb() {
console.log(this);
}
addEventListener('click', cb) {
// this --> DOM element
cb(); //=> console.log(this) --> DOM element
}
But, When i wrap logger.updateCount inside an anonymous function can corrent 'this' ?
btn.addEventListener('click', function (e) {
logger.updateCount(); //=> this -- point to 'logger' object
});
How come?
Just "imagine" how it would look to the inside of btn.addEventListener, probably like:
function addEventListener( eventString, callback ) {
// check the event
// if all is good
// set up an event object
// call back
callback(eventObject);
}
From this, you see that addEventListener only knows there is a callback function, but doesn't know if its this should be a specific object, or not.
And the way JS works, if just assumes that if it finds some object before the dot (like in the second example logger.updateCount()) it uses it as this, but if it doesn't... then you need to bind it to one, like:
btn.addEventListener('click', logger.updateCount.bind(logger) );
(this) in JavaScript is resolved based on the call site (how the function is invoked).
If the function is invoked as a method meaning if it is used like .func() then will be passed as this. logger.updateCount() is called in the event listener immaterial of from where it is called updateCount method will always receive logger object as this. this is hard-bound to logger object.
If the function object is passed as event handler or as a callback. The this is bound to DOM element where the event is triggered.
The this context that a function receives can be changed by using bind method as below:
logger.updateCount.bind()
In above case updateCount will always receives the targetObject that you sent as parameter as this context

how to create instances of a function in javascript?

Im trying to add an event listener to a object for example:
this.startLoading = function(){
this.a.addEventListener("complete", this.loadingHandler()); this gives me an error
},
this.loadingHandler = function(){
console.log("im doing something")
}
ERROR: "Uncaught Error: addListener only takes instances of
Function. The listener for event "complete" is "undefined"
However if I put the loadingHandler() function inside the scope it works, for example:
this.startLoading = function(){
var loadingHandler = function(){...}
this.a.addEventListener("complete", loadingHandler()); // this works
},
Im not sure what instances of a function means in that regard?
When you put () after a reference to a function, that means to call the function, and the value of the expression is whatever the function returns.
Your second example, that you say works, actually will not work, and you'll get the same error if the "startLoading" function is called.
Because you probably need to retain the proper context (this), what you probably need is
this.a.addEventListener("complete", this.loadingHandler.bind(this));
The .bind() method returns a function (exactly what addEventListener requires) that in turn will invoke your function such that this has the value requested.

Function getting called on the load of page

for (var key in obj[i]) {
dataDump[key] = textField.value;
var callback = function(zeKey){
return function(e){
dataDump[zeKey] = e.source.value;
};
}(key);
textField.addEventListener('change', callback);
}
When I load the window, this function gets called automatically, which I don't want and instead I want this to be called only when I do a change.
The main point is calling function(zeKey){...}(key). When you do so, key, which is a string is copied as a parameter (zeKey) to your anonymous function.
The following
var callback = function(zeKey){
return function(e){
dataDump[zeKey] = e.source.value;
};
}(key);
Calls the anonymous function with argument zeKey.
This anonymous function returns another function. This returned function is assigned to the callback.
If 1 what you mean by "the function is getting called" then this is expected behavior.
This entire code should be called only after DOM is ready. Place all these in a function and make sure the function is called only on window.onload or (jQuery's) .ready()
The function returned by the function will be called only during the callback.
Add these code once dom is created. If above code is inside a function, attach to window.load or write these code at the end of page.

Why is function() needed sometimes in JavaScript?

HTML
<button id='hello'>Click Me!</button>
JavaScript (wrong)
$('#hello').click(alert('Hello, World!'));
JavaScript (correct)
$('#hello').click(function() {
alert('Hello, World!');
}
I'm wondering why the first JS code triggers on the event load instead of click. Can anyone tell me why function() { [code] } is needed for the script to work properly?
In this example, I used jQuery events, but this is not specific to it, for example, I need to use it with setTimeout, too.
The click function expects another function as a parameter.
In the first case you would be passing the result of calling alert('hello world');, which is null.
The second is just a shorthand for:
$('#hello').click(callback);
function callback(){
alert('hello world');
}
Because .click() is a handler. The first argument is a function to assign. But if you actually pass the function with arguments then it will call the function (in this case alert) and then pass it's return value.
Writing $('#hello).click( function() { } )` is basically a short hand for writing:
var myfunction = function() {
// code
};
$('#hello').click( myfunction );
As you can see in the long hand way, it's passed as a reference to the function instead of the function's return value.
Your first example says "evaluate
alert('Hello, World!')
right now, and pass the result as an argument to click. "
The second says "Define a function which will do the alert when I call it, and pass that whole function as an argument to click.
The function() { ... } syntax is how you declare an anonymous function in Javascript. jQuery uses lots of these to specify that some action will be performed later, like when an event occurs. You can think of it as delaying the execution of your function until necessary. Without this syntax, whatever code you place there is evaluated immediately, which is not what you want for an event handler.
You might think, "why isn't JavaScript smart enough to know the difference?" Consider this:
function returnCallback(linkId, data) {
return function(e) {
alert('Clicked on ' + linkId + '. Here is some data: ' + data);
// Maybe do some stuff with e, the event parameter
}
}
$('#some-link').click(returnCallback('some-link', 'some-data'));
$('#other-link').click(returnCallback('other-link', 'different-data'));
This is a contrived example, but it illustrates the power of anonymous functions and closures. This works since returnCallback returns a function.
In the first instance, "JavaScript wrong", you're actually calling alert('Hello, World!') at the point that the script is loaded. Now, the reason you pass the .click function a function is because it can call it at any point. Essentially, you're packing code together to be run (or not run at all) at any point when you put it in a function.
$('#hello').click(alert('Hello, World!')); is attempting to run alert('...') and pass its return value to the .click() function which will not work as expected.
This is because JavaScript evaluates everything and during this process your alert is invoked. You can use anonymous function or you can also use your own custom function as implemented below:
<script language="javascript" type="text/javascript">
$("#mybutton").click(clickFired);
function clickFired() {
alert('click fired');
}
</script>
The parameter required for the .click() function is a Function. Therefore $("#hello").click(function { [code] }); is required. Because there's nothing to return by alert().
The click function here assigns a value to the event handler.
With the first ("wrong") code you're assigning a value of alert('Hello, World!') which is itself a function call, so it's going to be immediately evaluated and hence appear at load.
With the second ("correct") code you're now assigning a new anonymous function which is not executed itself, just instantiated at load. Hence this will work as expected later.
somefunction(alert('hello! world'));
this would mean you want to pass to somefunction the return value of alert("hello! world").
jquery click expects a callback that it should fire upon click on the element. so you put it in a function which does not execute unless someone (here jquery) calls it explicitly.

Categories