$ .proxy è un odore di codice?

1

Ho scritto la maggior parte delle mie applicazioni javascript in uno stile OO vicino a quello che userei per la maggior parte delle altre lingue. Tuttavia, questo significa che la maggior parte dei callback deve avere un riferimento a un oggetto e generalmente lo gestisco usando $ .proxy (o dojo.hitch, o qualunque sia lo strumento del framework per questo) per essere sicuro che i callback stiano funzionando in il contesto del mio oggetto, piuttosto che il tag a cui erano collegati.

Molto rapidamente, questo sembra portare all'uso di chiamate con proxy per quasi tutto e può sembrare che sto combattendo contro lo strumento, in particolare se lo strumento è jQuery.

Hai una politica su come gestire il binding di funzioni javascript nel tuo lavoro? Provi ad adattare il tuo design a come lo strumento associa le sue funzioni o forzare le associazioni a funzionare secondo il tuo progetto?

    
posta Dan Monego 18.04.2013 - 16:59
fonte

3 risposte

5

Bene, le alternative al binding delle funzioni sono molto peggiori, invece di una semplice chiamata $ .proxy, il l'alternativa popolare è digitarla ogni volta

var self = this;
$().click( function(e) {
    self.doit(e);
});

Rispetto a

$().click($.proxy(this.doit, this));

Ho una richiesta di funzione attiva per jQuery dove ciò sarebbe possibile:

$().click(this);

Questo è ciò che supporta il listener di eventi standard api :

elem.addEventListener("click", this);

Il metodo .handleEvent viene quindi chiamato su this quando si verifica l'evento, con un contesto appropriato. L'elemento come this è solo inutile perché può essere sempre raggiunto da event.currentTarget .

Quindi non è un odore di codice in quanto potresti sostituirlo con qualcosa di più semplice o migliore.

    
risposta data 18.04.2013 - 18:11
fonte
3

Se hai bisogno del contesto per più funzioni, sono d'accordo con la soluzione di Esailija. È comune e semplice.

Se ti serve solo una volta, questo è anche disponibile:

$().click( function(e) {
    this.do_something();
}.bind(this) );

Se do_something non accetta argomenti (quindi scarterà e ) e la funzione anonima la chiamerebbe solo, credo che funzioni anche:

$().click( this.do_something.bind(this) );
    
risposta data 18.04.2013 - 22:05
fonte
0

Se la funzione a cui stai vincolando è semplice (nessun valore di ritorno, nessun argomento), $ .proxy sembra l'opzione più semplice (in più ha altre funzionalità).

Tuttavia, dal momento che hai accennato al fatto che hai "scritto la maggior parte delle mie applicazioni javascript in uno stile OO vicino a quello che userei per la maggior parte degli altri linguaggi", consiglio vivamente TypeScript e la sua sintassi lambda. Ho fornito un esempio pertinente di seguito, ma prima, un'introduzione:

CoffeeScript, Google Dart e altri linguaggi più maturi hanno obiettivi simili, ma non ho familiarità con quelli: ciò che utilizzerai dipenderà dagli strumenti di sviluppo e dalle lingue con cui ti senti più a tuo agio. Se usi i linguaggi Microsoft e gli strumenti di sviluppo, TypeScript è probabilmente l'opzione migliore (gli IDE di JetBrains hanno anche un strong supporto per TypeScript).

Recentemente ho iniziato a implementare TypeScript nei miei progetti perché porta l'orientamento agli oggetti su JavaScript e funziona bene con i linguaggi lato server di .NET (il TypeLite open source rende facile generare automaticamente interfacce TypeScript da classi .NET: link ). Sebbene TypeScript sia un prodotto avviato da Microsoft, è un linguaggio open-source. Ad esempio, WebStorm IDE di JetBrains supporta TypeScript in modo più approfondito rispetto a Visual Studio; Io uso WebStorm insieme a Visual Studio per questo motivo.

Mi sono appena reso conto che il problema specifico di OO con $ .proxy è che non è possibile imporre argomenti del metodo strongmente tipizzati e valori di ritorno. Ma se si utilizza lambdas in TypeScript (sintassi che sarà disponibile in ECMAScript 6), può applicarlo senza scrivere tutto il codice aggiuntivo richiesto in ECMAScript 5. Ecco un lavoro Esempio di TypeScript:

interface ICallbackData{
Value1: boolean;
Value2: string; 
}

class Manager{
    private _CallbackProxy: (CallbackData: ICallbackData)=>string;
    constructor(){
        this._CallbackProxy = (CallbackData)=>this.CallbackHandler(CallbackData);
    }   
    CallbackHandler(CallbackData: ICallbackData): string{
        if (CallbackData.Value1){
            return CallbackData.Value2;
        }
        return "Other String";
    }

    Value: number;
    PerformActionThenCallback(){
        this.Value += 1;
        this._CallbackProxy(<ICallbackData>{Value1: true, Value2: "Callback String, Value: " + this.Value.toString()});
    }
}

Puoi vedere il codice JavaScript a cui quel codice verrà compilato collegandolo qui: link

TypeScript sarà pronto per il futuro di ECMAScript, quindi non dovrai riscrivere o aggiornare il tuo codice. Ad esempio, le funzioni lambda scritte in TypeScript si compilano attualmente in modo simile a quello scritto da Esailija (l'alternativa a $ .proxy):

var self = this;
$().click( function(e) {
    self.doit(e);
});

Si compila a questo perché sta cercando di essere compatibile con le implementazioni ECMAScript 5 di molti browser (attualmente può essere compilato per essere compatibile con ECMAScript 3 o 5, non sono sicuro del motivo per cui non viene compilato usando .bind () per ECMAScript 5 - questo è un argomento diverso). Ma quando ECMAScript 6 è molto diffuso, TypeScript lambdas si compilerà direttamente come lambda senza generare tutto quel codice aggiuntivo. Per ora, però, almeno ci sono robusti linguaggi OO che compilano JavaScript e semplificano i requisiti OO, eliminando al contempo la necessità di attendere ECMAScript 6 e oltre.

    
risposta data 11.09.2014 - 21:11
fonte

Leggi altre domande sui tag