-1

Why do I have to write

setTimeout(function() { $('#selector').focus() }, 100);

instead of

setTimeout($('#selector').focus, 100);

The latter gives me a TypeError this.trigger is not a function in Firefox, but clearly it is a function since typeof $('#selector').focus is "function." What's going on here?

Andrew
  • 867
  • 7
  • 20
  • might be helpful http://stackoverflow.com/questions/23640755/why-does-settimeout-require-anonymous-function-to-work – samnu pel May 12 '17 at 20:09

1 Answers1

4

This is because of the this problem. Per MDN documentation:

Code executed by setTimeout() is called from a separate execution context to the function from which setTimeout was called. The usual rules for setting the this keyword for the called function apply, and if you have not set this in the call or with bind, it will default to the global (or window) object in non–strict mode, or be undefined in strict mode. It will not be the same as the this value for the function that called setTimeout.

In JavaScript, there's a concept of "execution contexts", which are contexts that hold information about what is currently executing. There's a global execution context, and when a function is called, a new execution context is created. The this value then depends on the execution context and is set according to the current execution context. Since setTimeout creates a new execution context when the target function is called, this does not represent the jQuery object from the DOM, but the global object (as it is by default, or undefined in strict mode). Thus when jQuery internally calls this.trigger it is trying to call window.trigger which does not exist.

Try using Function#bind which explicitly sets the this value:

setTimeout($('#selector').focus.bind($('#selector')), 100);

Or, as Ryan mentions:

setTimeout($.fn.focus.bind($('#selector')), 100);

Of course, you could, as squint mentioned, use an arrow function instead, which is faster than using bind and more idiomatic:

setTimeout(() => $('#selector').focus(), 100);
Andrew Li
  • 55,805
  • 14
  • 125
  • 143