2010-07-04 18 views
27

Sto usando Javascript con jQuery. Mi piacerebbe implementare i parametri. In C#, sarebbe simile a questa:Il modo migliore per implementare i parametri in JavaScript?

/* 
* odp  the object to test 
* error a string that will be filled with the error message if odp is illegal. Undefined otherwise. 
* 
* Returns true if odp is legal. 
*/ 
bool isLegal(odp, out error); 

Qual è il modo migliore per fare qualcosa di simile in JS? Oggetti?

function isLegal(odp, errorObj) 
{ 
    // ... 
    errorObj.val = "ODP failed test foo"; 
    return false; 
} 

Firebug mi dice che l'approccio sopra funzionerebbe, ma c'è un modo migliore?

+0

Nick, ho so che è un po 'fa, ma credo di avere finalmente un [risposta] (https://stackoverflow.com/a/48517986/1016343) per voi. Sì, puoi eseguire i parametri in JavaScript. – Matt

risposta

13

Penso che questo sia praticamente l'unico modo (ma non sono un programmatore JavaScript hardcore;)).

Che cosa si potrebbe anche prendere in considerazione è quello di utilizzare una funzione di callback:

function onError(data) { 
    // do stuff 
} 


function isLegal(odp, cb) { 
    //... 
    if(error) cb(error); 
    return false; 
} 

isLegal(value, onError); 
+1

+1, questo è l'approccio più funzionale, tuttavia richiede di gestire immediatamente l'errore. È anche il più comune nella mia esperienza. – gradbot

33

L'approccio di callback di cui parla @Felix Kling è probabilmente la migliore idea, ma ho anche trovato che a volte è facile da sfruttare Javascript oggetto della sintassi letterale e appena hanno la funzione restituisce un oggetto in caso di errore:

function mightFail(param) { 
    // ... 
    return didThisFail ? { error: true, msg: "Did not work" } : realResult; 
} 

poi quando si chiama la funzione:

var result = mightFail("something"); 
if (result.error) alert("It failed: " + result.msg); 

Non elegante e difficilmente a prova di proiettile, ma sicuramente va bene per alcune situazioni semplici.

+0

+1, questo approccio è comune nelle chiamate JSON ma raramente l'ho visto nel codice. – gradbot

+1

+1 Mi piace questo ... – Julien

+1

Essendo entrato in questa pagina perché ero interessato a come Javascript potrebbe o non potrebbe gestire i parametri, sono deluso dalla risposta accettata. La possibilità di avere un tipo di ritorno definito insieme a uno a molti parametri out con tipi definiti è molto potente quando si programma una logica molto procedurale. Sfortunatamente, con la mia piccola reputazione non sono in grado di votare. –

13

Sì, come hai detto tu, gli oggetti sono il modo migliore e il solo per passare i dati per riferimento in JavaScript. Vorrei mantenere la vostra funzione isLegal come tale e semplicemente chiamare in questo modo:

var error = {}; 
isLegal("something", error); 
alert(error.val); 
+1

+1, questo è lo stile che più si avvicina a C#. – gradbot

+0

questo è ottimo .. –

3

c'è un altro modo di JS può passare 'fuori' dei parametri. ma credo che i migliori per la tua situazione siano già stati menzionati.

Gli array vengono anche passati per riferimento, non per valore. quindi, proprio come è possibile passare un oggetto a una funzione e quindi impostare una proprietà dell'oggetto nella funzione, quindi restituire e accedere alla proprietà di tale oggetto, è possibile passare in modo analogo una matrice a una funzione, impostare alcuni valori dell'array all'interno della funzione e restituire e accedere a tali valori all'esterno dell'array.

quindi in ogni situazione è possibile chiedersi "è meglio un array o un oggetto?"

+0

anche se questo è possibile, per motivi di chiarezza del codice nel codice chiamante, raccomanderei la risposta di @ Pointy: utilizzare un valore di ritorno sovraccarico in quanto è marginalmente più chiaro. – cmroanirgo

1

Non pubblicherò alcun code ma ciò che non viene eseguito qui in queste risposte è a mettere la rima al motivo. Sto lavorando nell'arena nativa di JS e il problema è sorto nel fatto che alcuni native API calls devono essere trasformati perché non possiamo scrivere i parametri senza brutti intrighi vergognosi.

Questa è la mia soluzione:

// Functions that return parameter data should be modified to return 
    // an array whose zeroeth member is the return value, all other values 
    // are their respective 1-based parameter index. 

That doesn't mean define and return every parameter. Only the parameters that recieve output.

La ragione di questo approccio è quindi: Multiple return values può essere necessario per qualsiasi numero di procedure. Ciò crea una situazione in cui gli oggetti con valori denominati (che alla fine non saranno sincronizzati con il contesto lessicale di tutte le operazioni), costantemente devono essere memorizzati per funzionare in modo appropriato con la/le procedura/e.

Utilizzando il metodo prescritto, basta conoscere what you called, e where you should be looking piuttosto che dover sapere cosa si sta cercando.

C'è anche il vantaggio che gli algoritmi "robusti e stupidi" possono essere scritti per avvolgere le chiamate della procedura desiderata per rendere questa operazione "più trasparente".

Sarebbe saggio per usare un object, function, o un array (che sono tutti gli oggetti) come parametro "write-back-output", ma credo che se ogni opera estranea deve essere fatto, si deve essere fatto da chi scrive il toolkit per semplificare le cose o ampliare le funzionalità.

Si tratta di un uno per tutti risposta per ogni sceglievamo, che mantiene APIs guardando il modo in cui dovrebbe in un primo sguardo, piuttosto che sembra essere e avere ogni rassomiglianza di un intreccio zoppicare-lastricata di spaghetti code arazzo che non riesco a capire se è una definizione o .

Congratulazioni, e buona fortuna.

Sto utilizzando il webkitgtk3 e interfacciato con alcuni proc nativi della libreria C. quindi questo esempio di codice comprovato potrebbe almeno servire allo scopo di illustrazione.

// ssize_t read(int filedes, void *buf, size_t nbyte) 
SeedValue libc_native_io_read (SeedContext ctx, SeedObject function, SeedObject this_object, gsize argument_count, const SeedValue arguments[], SeedException *exception) { 


    // NOTE: caller is completely responsible for buffering! 

        /* C CODING LOOK AND FEEL */ 


    if (argument_count != 3) { 
     seed_make_exception (ctx, exception, xXx_native_params_invalid, 
      "read expects 3 arguments: filedes, buffer, nbyte: see `man 3 read' for details", 
      argument_count 
     ); return seed_make_undefined (ctx); 
    } 

    gint filedes = seed_value_to_int(ctx, arguments[0], exception); 
    void *buf = seed_value_to_string(ctx, arguments[1], exception); 
    size_t nbyte = seed_value_to_ulong(ctx, arguments[2], exception); 

    SeedValue result[3]; 

    result[0] = seed_value_from_long(ctx, read(filedes, buf, nbyte), exception); 
    result[2] = seed_value_from_binary_string(ctx, buf, nbyte, exception); 

    g_free(buf); 
    return seed_make_array(ctx, result, 3, exception); 

} 
+0

Questa è un'ottima idea per restituire i parametri in JavaScript. Ha più senso per me. – Sunil

1

Il seguente è l'approccio che sto usando. E questa è la risposta a questa domanda. Tuttavia il codice non è stato testato.

function mineCoords(an_x1, an_y1) { 
    this.x1 = an_x1; 
    this.y1 = an_y1; 
} 

function mineTest(an_in_param1, an_in_param2) { 

    // local variables 
    var lo1 = an_in_param1; 
    var lo2 = an_in_param2; 

    // process here lo1 and lo2 and 
    // store result in lo1, lo2 

    // set result object 
    var lo_result = new mineCoords(lo1, lo2); 
    return lo_result; 
} 

var lo_test = mineTest(16.7, 22.4); 
alert('x1 = ' + lo_test.x1.toString() + ', y1 = ' + lo_test.y1.toString()); 
2

Sto usando un metodo di callback (simile a Felix Kling's approach) per simulare il comportamento di parametri out. La mia risposta differisce da quella di Kling in quanto la funzione di callback agisce come chiusura di acquisizione di riferimento piuttosto che come gestore.

Questo approccio presenta la sintassi della funzione anonima dettagliata di JavaScript, ma riproduce fedelmente la semantica dei parametri da altri linguaggi.

function isLegal(odp, out_error) { 
    //... 
    out_error("ODP failed test foo"); // Assign to out parameter. 
    return false; 
} 

var error; 
var success = isLegal(null, function (e) { error = e; }); 

// Invariant: error === "ODP failed test foo". 
0

L'approccio usuale per il caso d'uso specifica profilassi in Javascript, e in effetti lingue più alto livello, è di affidarsi a degli errori (aka eccezioni) per farvi sapere quando si è verificato qualcosa di fuori dal comune. Non c'è modo di passare un tipo di valore (stringhe, numeri, ecc.) Per riferimento in Javascript.

Vorrei farlo. Se è davvero necessario alimentare i dati personalizzati alla funzione di chiamata, è possibile creare una sottoclasse di Errore.

Le eccezioni di cattura sono un dolore, lo so, ma anche in questo caso si tiene traccia dei riferimenti.

Se davvero davvero bisogno di qualcosa che si avvicina al comportamento di fuori variabili, gli oggetti vengono passati per riferimento di default, e può comodamente acquisire i dati da altri scopes--

function use_out (outvar) 
{ 
    outvar.message = 'This is my failure'; 
    return false; 
} 

var container = { message : '' }; 
var result = use_out(container); 
console.log(container.message); ///gives the string above 
console.log(result); //false 

Penso che questo va un alcuni modi per rispondere alla tua domanda, ma penso che il tuo intero approccio sia rotto sin dall'inizio.Javascript supporta così tanti modi molto più eleganti e potenti per ottenere più valori da una funzione. Fai un po 'di lettura su generatori, chiusure, diavolo anche le callback possono essere carine in certe situazioni ... Guarda la continuazione passando allo stile.

Il mio punto con tutto questo rant è incoraggiare chiunque stia leggendo questo adattare il proprio stile di programmazione ai limiti e alle capacità del linguaggio che stanno utilizzando, piuttosto che cercare di forzare ciò che hanno appreso da altre lingue.

(BTW Qualcuno raccomanda con forza contro le chiusure perché causano il male effetti collaterali, ma non vorrei ascoltarli. Sono puristi. Gli effetti collaterali sono quasi inevitabili in un sacco di applicazioni senza un sacco di backtracking noioso e fare un passo intorno cant-get-ci-da-qui ostacoli. Se ne avete bisogno, mantenendo tutti insieme in un ambito lessicale ordinata, piuttosto che sparsi in una hellscape di puntatori oscuri e riferimenti suona molto meglio di me)

0

le risposte che ho visto finora non si sta implementando i punti principali in JavaScript, in cui sono utilizzati in C# (la parola chiave out). Sono semplicemente una soluzione alternativa che restituisce un oggetto in caso di errore.

Ma cosa fare se si ha realmente bisogno fuori parametri?

Poiché Javascript non lo supporta direttamente, è necessario creare qualcosa che sia vicino ai parametri di uscita di C#. Dai un'occhiata a questo approccio, sto emulando la funzione DateTime.TryParse di C# in JavaScript. Il parametro out è risultato, e perché JavaScript non fornisce una parola chiave out, sto usando .value all'interno della funzione per passare il valore di fuori della funzione (come ispirato da MDN suggestion):

// create a function similar to C#'s DateTime.TryParse 
 
var DateTime = []; 
 
DateTime.TryParse = function(str, result) { 
 
    result.value = new Date(str); // out value 
 
    return (result.value != "Invalid Date"); 
 
}; 
 

 
// now invoke it 
 
var result = []; 
 
if (DateTime.TryParse("05.01.2018", result)) { 
 
    alert(result.value); 
 
} else { 
 
    alert("no date"); 
 
};

Esegui lo snippet e vedrai che funziona. Si noti che result deve essere inizializzato come array vuoto [], prima si chiama la funzione. Questo è necessario perché all'interno della funzione si "inserisce" la proprietà .value.


Ora è possibile utilizzare il modello di cui sopra per scrivere una funzione come quella nella tua domanda (questo dimostra anche come emulare il nuovo parametro di scarto out _ in C#):

// create a function similar to C#'s DateTime.TryParse 
 
var DateTime = []; 
 
DateTime.TryParse = function(str, result) { 
 
    result.value = new Date(str); // out value 
 
    return (result.value != "Invalid Date"); 
 
}; 
 

 
// returns false, if odb is no date, otherwise true 
 
function isLegal(odp, errorObj) { 
 
    if (DateTime.TryParse(odp, [])) { // discard result here by passing [] 
 
    // all OK: leave errorObj.value undefined and return true 
 
    return true; 
 
    } else { 
 
    errorObj.value = "ODP failed test foo"; // return error 
 
    return false; 
 
    } 
 
} 
 

 
// now test the function 
 
var odp = "xxx01.12.2018xx"; // invalid date 
 
var errorObj = []; 
 
if (!isLegal(odp, errorObj)) alert(errorObj.value); else alert("OK!");

Nota: Invece di utilizzare un parametro di scarto come sopra indicato, in JavaScript è possibile als o Utilizzare un assegno di undefined, cioè all'interno della funzione effettua

if (result === undefined) { 
    // do the check without passing back a value, i.e. just return true or false 
}; 

Allora è possibile omettere result come parametro del tutto, se non necessario, così si potrebbe invocarlo come

if (DateTime.TryParse(odp)) { 
    // ... same code as in the snippet above ... 
}; 
Problemi correlati