2009-06-30 18 views
7

consente di dire ad esempio:In quale contesto viene richiamata la funzione di callback jQuery.post?

$(".button").click(function() { 

    $.post("commandrunner.php", 
     { 
      param1: 'value', 
      param2: 'value2', 
      param3: 'value3' 
     }, 
     function(data, textStatus) { 
      $(this).parent().after('<p>button clicked</p>'); 
     }, 
     "json" 
    ); 

}); 

ho corse questo e non ha funzionato. Ho provato un paio di cose prima di aver teorizzato che la richiamata non fosse invocata nel contesto di questo particolare ".button" e quindi $ (questo) era inutile. Questo ha funzionato invece:

$(".button").click(function() { 
    var thisButton = $(this); 

    $.post("commandrunner.php", 
     { 
      param1: 'value', 
      param2: 'value2', 
      param3: 'value3' 
     }, 
     function(data, textStatus) { 
      thisButton.parent().after('<p>button clicked</p>') 
     }, 
     "json" 
    ); 

}); 

Questo sembra un po 'un hack. È questo il modo giusto per ottenere un riferimento al pulsante cliccato? E quale contesto è quello (o qualsiasi altro callback) invocato in?

Grazie!

Ali

risposta

12

Quello che hai notato qui è il modo in cui funzionano le chiusure JavaScript. Come in altri linguaggi OO, quando viene invocato un metodo, ha un "questo", che è simile a Java this o Ruby self. Tuttavia, il codice JavaScript this è straordinariamente malleabile e jQuery sfrutta tale proprietà per impostarlo su un valore utile quando chiama la richiamata.

In caso di eventi, jQuery imposta il puntatore this in modo che punti all'elemento a cui è associato il gestore eventi. Check this out:

var hello = function() { 
    console.log("Hello " + this); 
}); 

Se venite da un background OO, si potrebbe guardare frammento di sopra con stupore: che cosa fa this punto. Per impostazione predefinita, punta all'oggetto globale (finestra nei browser). Ma si può facilmente ignorare che:

hello.call("world") // will print "Hello world" 

chiamata prende più argomenti dopo la this che sono passati come argomenti. Un metodo simile, chiamato apply, prenderà anche un this come primo argomento, ma accetta un array di argomenti come secondo parametro.

Ora, se guardiamo il tuo esempio di nuovo:

$(".button").click(function() { 

    $.post("commandrunner.php", 
     { 
      param1: 'value', 
      param2: 'value2', 
      param3: 'value3' 
     }, 
     function(data, textStatus) { 
      $(this).parent().after('<p>button clicked</p>') 
     }, 
     "json" 
    ); 

}); 

Il problema qui è che quando jQuery chiamò di nuovo la funzione, non ha chiamato con lo stesso this. Quando si crea una funzione anonima, questa verrà trattenuta su tutte le variabili locali nello stesso ambito, ma non su this, che viene impostata da JavaScript stesso (sull'oggetto globale) o sovrascritta quando viene chiamata.

Di conseguenza, la soluzione è di memorizzare un puntatore su this in una variabile locale, che sarà quindi disponibile per la chiusura.

La soluzione, come già detto, è:

$(".button").click(function() { 
    var parent = $(this).parent(); 
    $.post("commandrunner.php", 
    { 
     param1: 'value', 
     param2: 'value2', 
     param3: 'value3' 
    }, 
    function() { 
     parent.after('<p>button clicked</p>') 
    }, 
    "json" 
); 
}); 

In generale, quando immagazzino fuori un locale, immagazzino fuori dal set più specifico di elementi che posso, per rendere il codice callback più semplice. L'idioma comune jQuery è quello di fare var self = this, che è perfettamente bene pure.

Si noti inoltre che le funzioni JavaScript non controllano il numero di parametri, quindi è perfettamente legale lasciare i parametri vuoti se non si utilizza . Saranno comunque passati, ma la lista dei parametri vuota verrà semplicemente ignorata.

+0

+1 per selezionare elementi specifici anziché l'intero oggetto. –

+0

Grazie, questo ha risposto alla domanda. Ottimo libro a proposito. Ho imparato tutte le cose importanti su javascript dall'appendice! Inoltre, proveniente da un background OO/Java, ho lottato con chiusure per un po '. Avrei ragione nel ritenere che quanto sopra sia un esempio di chiusura? (ovvero che la funzione anonima nel callback post può accedere alle variabili nell'ambito della funzione anonimo che si chiude associata all'evento click e che questa è quindi una "chiusura") – Ali

+0

Tutte le funzioni in JavaScript, indipendentemente dal fatto che siano " re collegato agli oggetti, chiudere le variabili locali sul posto quando sono stati creati. Questo vale per le funzioni con nome (function foo() {}) e le funzioni anonime (function() {}). –

0

Questo è il giusto approccio al problema.

Il modo più semplice per scoprire il contesto sarebbe quello di utilizzare Firebug e console.log(this) — Tuttavia, sospetto che sarebbe l'oggetto XHR.

0

La parola chiave "questo" è legato alla validità di una funzione. Per fare riferimento a altri scopi genitore è necessario memorizzare il riferimento in opportune variabili di scoping, come var parentScope = this;

5

Secondo jquery api (sotto "richiamata Code FUNZIONI") l'oggetto this in qualsiasi funzione di callback JQuery AJAX punterà automaticamente alle impostazioni dell'oggetto Ajax o - se specificato - l'oggetto context.

Purtroppo non è possibile specificare un context a $ .post().

+0

puoi specificarne uno in $ .ajax, come: '$ .ajax ({ url: "test.html", contesto: document.body }). Done (function() { $ (this) .addClass ("done"); }); ' – cnlevy

Problemi correlati