2015-05-27 8 views
7

Ho un semplice JSFiddle here che dimostra il mio problema.Perdita di "questo" contesto in JavaScript quando si passa intorno ai membri

ho questo codice JavaScript:

var b = document.getElementById("b"); 

function A() { 
    this.f = "1"; 
} 

A.prototype.t = function() { 
    b.innerHTML = this.f; 
}; 

var a = new A(); 

var l = a.t; 
l(); 

Perché this indefinita quando provo a chiamare a.t? Come posso recuperare quel contesto senza essere troppo dettagliato o archiviare troppo?

risposta

12

Perché questo è indefinito quando provo a chiamare a.t?

Perché in JavaScript, this è impostato principalmente dal come la funzione si chiama, non dove è definito. a.t() imposta this a a all'interno della chiamata, ma l() imposta this su undefined (in modalità rigorosa) o sull'oggetto globale (in modalità libera).

Più (sul mio blog):

Le uniche eccezioni sono "legati" (come con Function#bind) o ES6 di "freccia" funzioni (che ottengono il loro this dal contesto in cui sono definiti).

Come si ripristina il contesto senza essere eccessivamente dettagliato o memorizzato troppo?

Function#bind è di solito una buona risposta:

var l = a.t.bind(a); 
l(); 

Si restituisce una nuova funzione che, quando viene chiamato, chiama l'originale con this insieme al primo argomento che hai dato bind. (Puoi anche associare altri argomenti.) È una funzione ES5, ma se hai bisogno di supportare browser molto vecchi, puoi facilmente aggiungerli in polifibrio.


Se avete solo bisogno di chiamatal con uno specifico valore this, e non hanno sempre utilizzare tale valore, come Robert Rossmann points out è possibile utilizzare Function#call o Function#apply:

l.call(this, 'a', 'b', 'c'); // Calls `l` with `this` set to `a` and args 'a', 'b', and 'c' 
l.apply(this, ['a', 'b', 'c']); // Calls `l` with `this` set to `a` and args 'a', 'b', and 'c' -- note they're specified in an array 
+1

In alternativa, si può usare ['Funzione.prototype.call'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) se la funzione non ha bisogno di essere passata in giro e ha solo bisogno di essere chiamata una volta: 'var l = at; l.call (a); ' –

+0

Per quanto riguarda il codice del richiedente originale, sarebbe valido se' A.t() 'fosse definito all'interno della funzione' A' originale? In questo modo la funzione sarebbe in grado di accedere a una variabile con ambito privato ([come questo] (http://jsfiddle.net/lun471k/re8vdadt/1/)). –

+0

@RobertRossmann puoi dimostrarlo? – eatonphil

1

JavaScript è funzionalmente scope,

Per eseguire una funzione con il valore corretto per questo, è necessario associarlo all'oggetto giusto. Ad esempio,

var l= a.t.bind(a); 
0

Poiché il contesto cambia quando si assegna la funzione a una nuova variabile. Puoi sempre fare semplicemente a.t();.

Problemi correlati