2009-04-02 18 views
25

Il comportamento di "questo" quando viene chiamata la funzione bar mi sconcerta. Guarda il codice qui sotto. C'è un modo per fare in modo che "questo" sia una semplice istanza di vecchio js quando la barra viene chiamata da un gestore di clic, invece di essere l'elemento html?jQuery/JavaScript "questo" confusione puntatore

// a class with a method 

function foo() { 

    this.bar(); // when called here, "this" is the foo instance 

    var barf = this.bar; 
    barf(); // when called here, "this" is the global object 

    // when called from a click, "this" is the html element 
    $("#thing").after($("<div>click me</div>").click(barf)); 
} 

foo.prototype.bar = function() { 
    alert(this); 
} 
+0

Spiega che "questo" è l'istanza di foo. Il seguente jsfiddle (http://jsfiddle.net/yY6fp/1/) dimostra che 'this' in' this.bar() 'valuta l'oggetto' window' (globale). –

risposta

33

Benvenuti nel mondo di javascript! : D

Hai vagato nel regno dell'ambito javascript e della chiusura.

Per il breve risposta:

this.bar() 

viene eseguita nell'ambito della foo, (come questo riferisce a foo)

var barf = this.bar; 
barf(); 

viene eseguita sotto la portata globale.

this.bar significa sostanzialmente:

eseguire la funzione indicata da this.bar, nell'ambito di questa (foo). Quando si copia this.bar in barf e si esegue barf. Javascript inteso come, eseguire la funzione puntata da barf, e poiché non c'è questo, viene eseguito solo in ambito globale.

Per correggere questo, è possibile cambiare

barf(); 

a qualcosa di simile:

barf.apply(this); 

Questo dice Javascript per legare l'ambito di questo a vomitare prima di eseguirlo.

Per gli eventi jQuery, è necessario utilizzare una funzione anonima oppure estendere la funzione di bind in prototipo per supportare l'ambito.

Per maggiori informazioni:

+2

Non sono sicuro al 100% sulla terminologia, ma penso che questa risposta (e le risorse collegate) confondano 'ambito' con 'contesto di esecuzione'. L'oggetto puntato da 'this' è il * contesto di esecuzione *, ed è completamente indipendente da * scope * (con cui le chiusure hanno a che fare). L'ambito è determinato al momento della creazione di una funzione e determina quali variabili può vedere la funzione; il contesto di esecuzione viene determinato ogni volta che viene chiamata la funzione e determina a cosa si riferisce questo. Sostituisci 'ambito' con 'contesto di esecuzione' ovunque qui e solo allora sarà corretto - Penso! –

1

Questo perché questo è sempre il caso che la funzione è attaccato. Nel caso di EventHandler è la classe che ha attivato l'evento.

Si può aiutare la vostra auto con una funzione anonima come questa:

function foo() { 
    var obj = this; 
    $("#thing").after($("<div>click me</div>").click(function(){obj.bar();})); 
} 

foo.prototype.bar = function() { 
    alert(this); 
} 
2

Si può usare Function.apply sulla funzione per impostare ciò che this dovrebbe fare riferimento a:

$("#thing").after($("<div>click me</div>").click(function() { 
    barf.apply(document); // now this refers to the document 
}); 
+1

Oltre al fatto che nel codice manca una parentesi chiusa, la funzione * apply * esegue istantaneamente la funzione * barf * invece di restituire un puntatore a funzione. – Martin

+0

Grazie, ho corretto il post :) – moff

5

C'è una buona spiegazione su this parola chiave in JavaScript disponibile presso QuirksMode.

0
this.bar(); // when called here, "this" is the foo instance 

questo commento è sbagliato quando foo viene utilizzata come una normale funzione, non come un costruttore. qui:

foo();//this stands for window 
Problemi correlati