jairhumberto
jairhumberto

Reputation: 614

detail about javascript callbacks

I am curious about something, imagine a link that closes the window. See the code below, and read the comments:

var a = document.querySelector('a');

//
// Since a.onclick requires a callback I have the following code:
//

a.onclick = function() { window.close() }; // This works fine.
a.onclick = function() { close() }; // This works as well.
a.onclick = () => { close() }; // This also work.
a.onclick = () => close(); // This works.

// But...

a.onclick = window.close; // This doesn't work.
a.onclick = close; // Neither this.

// But, why not?? Since onclick requires a function, and window.close is a 
// function and close is just the shorten way to call window.close?

// However...

a.onclick = close.bind(); // This works fine....

So fellows, since onclick receives a function, why to set just "close" does not do the job? It should "register" the function close (window.close) as the "callback" for that action, and call it when the event was triggered (like close.call());

I really don't understand this behavior

Upvotes: 1

Views: 36

Answers (2)

slebetman
slebetman

Reputation: 114014

This is a bit tricky.

We are so used to seeing window holding all global variables that we have forgotten that window itself is an object. That's right - it's the object that represent the browser window.

And close is not merely a function but a method of the window object (see: https://developer.mozilla.org/en-US/docs/Web/API/Window/close).

Thus when you convert close to a function reference it loses it's binding to this (which should point to window).

The others work by happenstance:

  1. a.onclick = function() { window.close() };

    This is obvious. You're calling the method directly so it gets the correct this.

  2. a.onclick = function() { close() };

    A function that does not belong to any object will have it's this either pointing to the global object (window) or undefined if in strict mode. So when not in strict mode this will work.

  3. a.onclick = () => { close() };

    Same explanation as number 2.

  4. a.onclick = () => close();

    Same explanation as 3 but not using the optional {}.

Note: One may be tempted to think that 2, 3 and 4 are different mechanisms but while arrow functions affect how this behave you're not calling this.close(). Thus only the this value in close is important. The arrow functions don't change that.

Note that when not in strict mode the following should also work:

a.onclick = () => { this.close() }

I think it's fairly obvious from my previous explanations why the above should work.

Upvotes: 4

Jacob
Jacob

Reputation: 78920

It's all about the binding of the method to its this. When you have a Function reference to a method, then call it, it won't "know" which object the method belongs to (this will no-longer be a Window), so if .close() needs to know about its window object, the function call will fail.

bind works around this by fixing this to a particular object:

a.onclick = window.close.bind(window);

Upvotes: 2

Related Questions