2012-05-31 18 views
29

Mi piacerebbe una certa comprensione nell'errore che sto vedendo in Safari e Chrome con la seguente riga di codice:Perché non posso passare "window.location.reload" come argomento a setTimeout?

setTimeout(window.location.reload, 250);

Chrome riporta:
Uncaught TypeError: Illegal invocation

e Safari:
TypeError: Type error

In FireFox, il codice funziona correttamente. Inoltre, questo codice funziona bene in ciascuno dei tre browser:

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

Chrome e Safari hanno problemi con questo codice:

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

La particolarità di window.location.reload che causa questo errore?

(non so se è utile o no, ma ecco un jsfiddle che illustra questo)

risposta

49

perché reload() esigenze window.location come this. In altre parole, è un metodo di window.location. Quando si dice:

var fun = window.location. reload; 

fun(); 

Si sta chiamando reload() funzione senza alcun this di riferimento (o con implicita window di riferimento).

Questo dovrebbe funzionare:

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

La parte window.location.reload.bind(window.location) significa: prendere window.location.reload funzione e restituire una funzione che, quando viene chiamato, utilizzerà window.location come this riferimento all'interno reload().

Vedi anche

+0

le marche Senso perfetto. Buono a sapersi. Qualche ipotesi sul perché funziona in Firefox? – goggin13

+0

@ goggin13: interessante ... non sicuro. Ma certamente questo non è portatile. –

+0

Giusto, solo curioso. Grazie per la spiegazione '.bind', molto istruttiva! – goggin13

3

Perché this deve essere associato a location quando si chiama reload. E 'uguale a cercare:

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

this sarebbe window in modalità non rigorosa e undefined in modalità rigorosa che sono entrambi validi.

in non-vecchi browser che si possono fare, invece:

reload.call(location)

o nel tuo esempio:

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

più vecchio IE non supportano esplicitamente vincolanti sull'ospite oggetti però.

È inoltre possibile ottenere questo per alcuni metodi nativi che non sono generici come ad esempio:

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

Alcuni sono generici:

var fakeArray = {0:1,1:2,length:2}; 
fakeArray.join = [].join; 
fakeArray.join(" "); 
"1 2" 
2

questo non riesce, perché ti manca la location contesto (la funzione del this), quando si passa a modo tuo. Si dovrà bind contesto, prima di poter usare in questo modo, ad esempio con il underscore.js bind method

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

E 'lo stesso con qualsiasi altra funzione che di solito è chiamato dal suo contenente oggetto come console.log

+0

non suggerirei di inserire un'intera libreria per una funzione che esiste già in modo nativo comunque. – jbabey

+0

@jbabey hai ragione se si assume che il browser supporti JavaScript 1.8.5, dove è stato introdotto 'bind'. Per compatibilità con le versioni precedenti, mi attenersi a underscore.js o, se piace, Prototype. – Tharabas

+0

apply o call potrebbe essere usato (e probabilmente dovrebbe) anziché bind – jbabey

Problemi correlati