57

I would love some insight into the error I am seeing in Safari and Chrome with the following line of code:

setTimeout(window.location.reload, 250);

Chrome reports:
Uncaught TypeError: Illegal invocation

And Safari:
TypeError: Type error

In FireFox, the code runs fine. Also, this code runs fine in each of the three browsers:

setTimeout((function() {
  window.location.reload();
}), 250);

Chrome and Safari have no issues with this code:

var say_hello = function () { alert("hello") };  
setTimeout(say_hello, 250);  

What is special about window.location.reload that causes this error?

(not sure if it's useful or not, but here's a jsfiddle illustrating this)

goggin13
  • 7,876
  • 7
  • 29
  • 44

4 Answers4

97

Because reload() needs window.location as this. In other words - it is a method of window.location. When you say:

var fun = window.location.reload;

fun();

You are calling reload() function without any this reference (or with implicit window reference).

This should work:

setTimeout(window.location.reload.bind(window.location), 250);

The window.location.reload.bind(window.location) part means: take window.location.reload function and return a function that, when called, will use window.location as this reference inside reload().

See also

Andrew-Dufresne
  • 5,464
  • 7
  • 46
  • 68
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
8

There is another way of doing this, pretty simple, and no need of doing extra steps, bindings or stuff like that. When you use arrow functions instead of common functions in JS, the this context is included. So you could just as easily do the following:

setTimeout(() => window.location.reload(), 250);
Javi Marzán
  • 1,121
  • 16
  • 21
3

Because this must be bound to location when you call reload. It's same as trying:

var reload = window.location.reload;
reload();

this would be window in non-strict mode and undefined in strict mode which are both invalid.

in non-old browsers you can do instead:

reload.call( location )

or in your example:

setTimeout( window.location.reload.bind( window.location ), 1000 )

Older IEs don't support explicit binding on host objects though.

You also get this for some native methods which are not generic such as:

var a = function(){}.toString;
a();
TypeError: Function.prototype.toString is not generic

Some are generic:

var fakeArray = {0:1,1:2,length:2};
fakeArray.join = [].join;
fakeArray.join( " " );
"1 2"
Esailija
  • 138,174
  • 23
  • 272
  • 326
2

This fails because you're missing the location context (the function's this), when passing it your way. You would have to bind the context, before you can use it like this, for example with the underscore.js bind method

var boundReload = _.bind(window.location.reload, window.location);
setTimeout(boundReload, 500)

It's the same with any other function that is usually called from it's containing object like console.log

Tharabas
  • 3,402
  • 1
  • 30
  • 29
  • 2
    i would not suggest bringing in an entire library for a function that already exists natively anyways. – jbabey May 31 '12 at 19:50
  • @jbabey you're right if you assume that the browser supports JavaScript 1.8.5, where `bind` was introduced. For backward compatibility I'd stick to underscore.js or, if one likes it, Prototype. – Tharabas May 31 '12 at 19:54
  • apply or call could (and probably should) be used instead of bind – jbabey May 31 '12 at 20:00
  • 1
    `apply` and `call` would execute the `reload` function immediately, and I doubt that what goggin13 wanted ;) – Tharabas May 31 '12 at 20:06
  • you would put them in the anonymous function, just like he posted in his question – jbabey May 31 '12 at 20:12
  • 1
    If you're using an anonymous function, there is no need for `apply` or `call`, you could just use `window.location.reload()` – Tharabas May 31 '12 at 20:15