2010-10-26 11 views
8

io voglio fare questo in Javascript:Facendo riferimento a "questa" chiusura in un genitore in javascript

function Z(f) 
{ 
    f(); 
} 

function A() 
{ 
    this.b = function() 
    { 
    Z(function() { this.c() }); 
    } 

    this.c = function() 
    { 
    alert('hello world!'); 
    } 
} 

var foo = new A(); 
foo.b(); 

Può essere compiuta in questo modo:

function Z(f) 
{ 
    f(); 
} 

function A() 
{ 
    var self = this; 
    this.b = function() 
    { 
    Z(function() { self.c() }); 
    } 

    this.c = function() 
    { 
    alert('hello world!'); 
    } 
} 

var foo = new A(); 
foo.b(); 

C'è un modo migliore?

risposta

6

Mantenere un riferimento al genitore (come avete) è un buon approccio, tuttavia per il tuo esempio specifico non c'è bisogno per il wrapper anonimo, è possibile passare alla funzione direttamente, in questo modo:

var self = this; 
this.b = function() 
{ 
    Z(self.c); 
} 

You can test it out here, e senza questo involucro c'è in realtà alcuna necessità per la variabile self, si può semplicemente utilizzare this direttamente, in questo modo:

this.b = function() 
{ 
    Z(this.c); 
} 

You can test that version here.


Dal momento sembra che ci sia una certa confusione nei commenti qui sotto, il codice sopra mantiene thisper la domanda, se si vuole mantenere la this/contesto all'interno del callback così, utilizzare .call()like this:

this.b = function() 
{ 
    Z.call(this, this.c); 
} 

E per Z:

function Z(f) 
{ 
    f.call(this); 
} 

You can test it here.

+0

destro, in questo semplice esempio, non v'è alcuna ragione per il wrapper. Non dovrebbe essere difficile concepire un esempio in cui è necessario. (Modifica dei parametri, ecc.) Se non si avvolge, tuttavia, presumo che la chiusura sia passata come ci si aspetterebbe? –

+2

senza il wrapper anonimo, 'c' viene chiamato con il riferimento' this' sbagliato. – Lee

+0

@ Jonathan - Sì, corri, in tal caso vorrai passare una variabile proprio come se fossi in "self" che ti permetta di accedere a ciò che è nella chiusura. –

1

C'è uno schema che viene spesso chiamato "Delega", che risolve questo problema.

in JavaScript, un'implementazione non troppo di fantasia potrebbe essere simile a questa:

/** class Delegate **/ 
var Delegate = function(thisRef, funcRef, argsArray) { 
    this.thisRef=thisRef; 
    this.funcRef=funcRef; 
    this.argsArray=argsArray; 
} 
Delegate.prototype.invoke = function() { 
    this.funcRef.apply(this.thisRef, this.argsArray); 
} 
/** static function Delegate.create - convenience function **/ 
Delegate.create = function(thisRef, funcRef, argsArray) { 
    var d = new Delegate(thisRef, funcRef, argsArray); 
    return function() { d.invoke(); } 
} 

Nel tuo esempio, si usa in questo modo:

this.b = function() { 
    Z(Delegate.create(this, this.c)); 
} 

si potrebbe anche scrivere funzioni che si aspettano di ricevere un delegato:

function Z(d) { 
    d.invoke(); 
} 

quindi, nel A, il tuo impl di b diventa:

this.b = function() { 
    var d = new Delegate(this, this.c); 

    Z(d); 
    SomeOtherFunc(d); 
} 

Il Delegate fornisce solo un modo semplice, coerente di incapsulare il riferimento this (che hai chiamato self), all'interno di un'istanza di un oggetto che può essere affrontato come qualsiasi altro istanza di oggetto. È più leggibile e ti impedisce di dover inquinare l'ambito della tua funzione con variabili superflue come self. Un'implementazione delegata più elaborata potrebbe avere i propri metodi e altri stati correlati. È anche possibile creare il delegato in modo tale da ridurre al minimo alcuni problemi di gestione della memoria relativi all'ambito (anche se il codice che ho mostrato qui non è sicuramente un esempio).

+0

Non penso che funzioni: 'Z (function() {Delegate.create (this, c)});'. Senza il wrapper, non c'è bisogno di 'self' e nessun motivo per il delegato perché è più breve scrivere' Z (this.c); '. –

+0

@ Jonathan - hai aggiunto un ulteriore wrapper che non è nel mio esempio. è solo 'Z (Delegate.create (this, c))'; Ho espanso un po 'l'esempio Delegato in modo che sia più flessibile e più chiaro di quello che sta succedendo. – Lee

+0

@Jonathan - 'Z (this.c)' funzionerà, a patto che non ti interessi quale oggetto 'this' faccia riferimento quando viene eseguito all'interno di' c'. Il codice che hai mostrato non usa 'this' all'interno di' c', quindi non presenterà alcun problema. Se controlli (questa leggera modifica dell'esempio di @ Nick) [http://jsfiddle.net/UQpnX/], vedrai il potenziale problema risolto dal wrapper anonimo, nel tuo esempio originale - o con un costrutto più formale come il delegato. Qualunque dei due va bene. – Lee

1

È possibile in alternativa utilizzare

this.b = function() 
{ 
    Z((function() { this.c() }).apply(this)); 
} 
Problemi correlati