2012-01-07 13 views
20

JavaScript è preteso di avere funzioni di prima classe, quindi questo sembra il seguente dovrebbe funzionare:Se JavaScript ha funzioni di prima classe, perché non chiama questa funzione in una variabile?

var f = document.getElementById; 
var x = f('x'); 

ma fallisce su tutti i browser, con un diverso messaggio di errore criptico su ciascuno di essi. Safari dice "Errore tipo". Chrome dice "invocazione illegale". Firefox dice "Impossibile convertire l'argomento JavaScript".

Perché?

risposta

19

Perché in JavaScript le funzioni non sono associate al contesto (this). È possibile utilizzare bind():

var f = document.getElementById.bind(document); 
+4

Per chiarire questa risposta, 'this' in' documento .getElementById() 'è' document', mentre 'this' dove stai eseguendo il tuo scope è l'ambito globale, noto anche come' this' è l'oggetto 'window'. –

36

Quando si chiama obj.method() in Javascript il metodo viene passato obj come this. Chiamando document.getElementById('x') con quindi impostato this a document.

Tuttavia, se basta scrivere f = document.getElementById adesso avete un nuovo di riferimento alla funzione, ma che il riferimento non è più "legato" a document.

Quindi il tuo codice non funziona perché quando chiami f come un nome di funzione nuda finisce legato all'oggetto globale (window). Non appena l'interno della funzione tenta di utilizzare this, rileva che ora ha uno window anziché uno document e non sorprende che non gli piaccia.

È possibile far f lavoro se lo si chiama così:

var x = f.call(document, 'x'); 

che chiama f ma esplicitamente imposta il contesto per document.

Il modo ad altri di risolvere questo problema è quello di utilizzare Function.bind() che è disponibile solo in ES5:

var f = document.getElementById.bind(document); 

ed è in realtà solo una scorciatoia generalizzato per creare il proprio wrapper che imposta correttamente il contesto:

function f(id) { 
    return document.getElementById(id); 
} 
3

Utilizzando operatore diffusione di ES6, si potrebbe anche provare:

function f(){ 
    return document.getElementById(...arguments); 
}; 

Babel dà questo:

function f() { 
    var _document; 
    return (_document = document).getElementById.apply(_document, arguments); 
}; 
Problemi correlati