Let's dissect this step-by-step.
General information
The .addEventListener
function/method takes in 2 (or 3) arguments:
- a
String
, with a value of the event type/name (for example "click"
)
- a pointer to a
Function
, which should be executed when the event occurs
- a
Boolean
, specifying if event bubbling or event propagation should be used. This argument is optional and can be omitted.
Example 1
In you first example, you pass a String
("click"
) and a pointer to a Function
(eventFunction
) into .addEventListener
. Everything works as expected, the event occurs and the function is executed.
Example 2
In this example, you pass a String
and undefined
to .addEventListener
, which is not what .addEventListener
expects. You might ask yourself "When did I pass in undefined
?". Well, it happened as soon as you executed your eventFunction
by adding parens ()
after it. Here, the syntax in JS is equal to the syntax in most other languages, adding parens to the right side of a function executes the function.
Because your eventFunction
doesn't return anything explicitly, it automatically returns undefined
. Therefor, this is what .addEventListener
got:
clicker.addEventListener("click", undefined)
However, because you executed eventFunction
, it logs "It worked"
to the console once.
Example 3
This example fails for the same reasons example 2 failed.
Example 4
The code in the last example works, because it uses a concept called closure. There are literally thousands of explanations of the concept, so my explanation here will be really short. If you have trouble understanding it, just google for
"javascript closures".
In contrast to a lot of other languages, JavaScript has function scoping instead of block scoping. So if you define a variable inside a function F
and return another function G
from within F
, G
will have access to variables and arguments from inside F
. For demonstration purposes:
function F () {
var fVariable = 'Defined in F';
return function G () {
return fVariable; // <-- this is the closure
}
}
var funcG = F(); // <-- execute F
funcG(); // -> 'Defined in F';
Compare this short example with your fourth code: They are pretty much the same. The only difference is, that your code creates an extra function func
.
Now, if you call clicker.addEventListener("click", eventFunction("it works"))
,
you execute eventFunction
, which returns another (anonymous/lambda) function which encapsulates the "it works"
string via a closure. If we write it out by hand, this is what .addEventListener
"sees":
clicker.addEventListener("click", function (event) {
func("it works", event);
});
EDIT: Solving the problem
Here's a working example, note that I changed the function names to reflect their purpose:
function eventHandlerFactory (myStr) { // <-- eventFunction in your code
return function executeOnEvent (event) { // <-- executed if an event occurs
console.log(myStr);
console.log(event);
}
}
clicker.addEventListener("click", eventHandlerFactory("it worked"));
The eventHandlerFactory
function returns a function executeOnEvent
, which is passed into .addEventListener
. Writing it out by hand again, this is what the interpreter understands:
clicker.addEventListener("click", function executeOnEvent (event) {
console.log("it works");
console.log(event);
});