Reputation: 405
for my own personal improvement, I was fiddling with closures and functions in JS, when I found this behaviour that deeply puzzles me.
Take this function, assign it to a variable, and call it from two different HTML elements via jQuery:
var print = function(){
console.log("Hello" );
};
document.getElementById('element1').onclick = print();
document.getElementById('element1').onclick = print;
Why on earth is the second element, if clicked, to be the one that prints correctly "hello"?
I always thought you need to put brackets after a function's name to call it.
In fact, if I just call the function by itself (and not via a jQuery event) it works as expected:
var print = function(){
console.log("Hello" );
};
print; //does nothing
print() //prints "Hello"
What I am missing here? Is something related to jQuery? Thanks in advance!
Upvotes: 2
Views: 2498
Reputation: 28548
you have to bind reference of a function to onclick
but in first case you actually doing nothing other than calling a function:
document.getElementById('element1').onclick = print();
It will actually invoke the function print()
and since function has nothing in return so it will not impact on element1 click event.
on the other hand
document.getElementById('element1').onclick = print;
In order to make first case working you need to return a function so it can be invoked on event:
var print = function() {
// when this will invoke it will return function
return function() {
console.log("Hello");
};
};
will assign reference of function to onclick event and it invoke the function on each click event.
Upvotes: 0
Reputation: 5156
A function is just like any other variable, except it has an additional operator:
Just like with objects and arrays, you can use the dot and square-brace operators to retrieve their properties, you can use the call operator to call the function, but that function is still a variable nevertheless.
function a() {
console.log("potato");
}
var b = a;
b() //prints "potato" on the console
On your example, using the print
function on its own (without the call operator did nothing, but that would be the same as if you wrote a number on its own: the result is the value itself!
console.log(a); //prints function a()
console.log(42); //prints 42
When you type a something on its own line, it's just going to return that value to the expression, but without anything to do, nothing happens:
a; //nothing happens
42; //nothing happens
Now, when you use the call operator, it runs your function and the expression's value is whatever the function return
ed, or undefined
if it didn't return anything.
function doStuff() {
return "potato";
}
Now suppose you have this expression:
console.log(doStuff());
It will run doStuff
, and return to the expression:
console.log("potato");
Then it will run console.log
, with "potato"
as its parameter, and it will do its magic to show on the console.
Events are just like that, saving a function to a variable to use later:
function doom() {
return Infinity / 0;
}
onDoomsday = doom;
//somewhere else in your code:
onDoomsday(); //destroys the world
Upvotes: 0
Reputation: 82287
Using
document.getElementById('element1').onclick = print();
is equivalent to the value returned from print (but there is no returned value, so it is undefined)
document.getElementById('element1').onclick = undefined;
When the onclick event handler is called, it calls the assigned value expecting a function. undefined()
will also give you the same error. print()
will do what you were expecting, and that is why when you use this it works
document.getElementById('element1').onclick = print;
Upvotes: 0
Reputation: 160191
(Too long for comment.)
If you really want to mess with your own head:
var print = function() {
return function() {
console.log("Hello");
};
};
document.getElementById('element1').onclick = print();
This will do what you expect, but perhaps not why you expect it to.
Upvotes: 0
Reputation: 48277
The difference is calling a function vs taking a reference to a function.
The syntax func()
immediately calls the function provided. In element.onclick = func()
, the event will be bound to the return value of func
.
With element.onclick = func
, you are not calling func
, simply referencing it and assigning it to the event.
If func
happened to return a function, then you could use the element.onclick = func()
syntax, and it would do what you expect.
document.getElementById('element1').onclick = print(); // Assigns the *return value* of print
document.getElementById('element1').onclick = print; // Assigns print
function returnPrinter() {
return function print() {
// do stuff
}
}
document.getElementById('element1').onclick = returnPrinter(); // Assigns the return value, which is a function, thus doing what you want
Upvotes: 8