0

There is an example in "Head first JavaScript" book. This piece of code is unblurring an image on click. The code works, but I don't understand how, though it's an extremely simple piece of code.

The function init is called when a window is loaded. getElementsByTagName gives an HTMLCollection. A click on an image invokes a showAnswer function. Now there is a mystery for me.

window.onload = init;
function init() {
    var images = document.getElementsByTagName("img");
    for (var i = 0; i < images.length; i++) {
        images[i].onclick = showAnswer;
    }
};

function showAnswer(e) {
    var image = e.target;
    var name = image.id;
    name = name + ".jpg";
    image.src = name;
}
  1. There should be a parameter e. How this parameter is being created, from where? When showAnswer is called in init, there are no parameters given to it.
  2. Considering the fact that I'm using a .target method on it, it should be an object. How does the browser know that this object has name e?
  3. Why images[i].onclick = showAnswer; and not showAnswer();?
  • 1
    "showAnswer" is **not** called in init. Its _reference_ is assigned to an element's "click" handler. When the click event is emitted, the agent (browser) calls the handler (showAnswer) passing the event to it as the first argument. Note the difference: `images[i].onlick = showAnswer` assignes a reference of "showAnswer" to "onlclick". It means "showAnswer" will be called on click event, vs. `images[i].onclick = showAnswer()` would assign the _return value_ of showAnswer to the click handler. – marekful Feb 06 '19 at 15:42

2 Answers2

3

images[i].onclick = showAnswer is defining the event handler function to be run when images[i] is clicked. If you were to use showAnswer() there, it would run immediately in the init function which is probably not what you want.

images[i].addEventListener('click', showAnswer) is another way to write that, which might be more intuitive.

Event handler functions pass in an event object, which is what the 'e' is referring to. 'e.target' is referring to the element itself.

A reference for DOM events: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events

Ian Wotkun
  • 68
  • 6
0

(breaking myself of the habit of answering questions in comments...)

There should be a parameter e. How this parameter is being created, from where?

When you do images[i].onclick = showAnswer, that assigns "showAnswer" as the event handler for the "click" event for the DOM element named in images[i].

Later, when the user clicks that element (or the event gets triggered by some other method), the browser constructs the Event object, which contains a whole lot of information about that specific event. It then calls your event handler, passing along the Event object as the first (and only) parameter.

When showAnswer is called in init, there are no parameters given to it.

In your init function, you don't call showAnswer; you assign it as the event handler for clicks on images. The event is what passes the parameter to the handler, not your init.

Considering the fact that I'm using a .target method on it, it should be an object. How does the browser know that this object has name e?

That's the name you gave the parameter in the function. You could use any name, but e or evt are a common convention for event objects.

Why images[i].onclick = showAnswer; and not showAnswer();?

If it were showAnswer() you'd be assigning the return value of the function to the click handler. (Which in this case would be undefined, because showAnswer doesn't return anything.) With showAnswer you assign the function itself to the handler.

Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
  • _The event is what passes the parameter to the handler, not your init._ So, breaking it to very simple words. Event object is created because there is an event handler. Browser knows, that if there is a function handling any event, that function should be given all the information about this event (as an object). And I use 'e' to access event's 'target' property , as i would access any other objest's property with 'object.property'? – Volodymyr Berestovskyy Feb 06 '19 at 16:43
  • That's pretty close, yeah. I've expanded the answer a bit. – Daniel Beck Feb 06 '19 at 19:01