Qual è il vantaggio di una funzione senza parametri che chiama solo un'altra funzione

21

Un tutorial (per Javascript) che sto facendo suggerisce che scriviamo una funzione come questa:

function sayHello() {
   //Some comments explaining the next line
   window.alert("Hello");
}

Oltre all'offuscamento ci sono benefici per scrivere qualcosa di simile nella vita reale? Se sì, quali sono i vantaggi?

    
posta Daniel 02.10.2014 - 01:56
fonte

8 risposte

60

Per favore perdona la mia memoria se ho questo errore ... Javascript non è la mia lingua di implementazione preferita.

Ci sono diversi motivi per cui si vorrebbe avere una funzione no arg a capo di un'altra chiamata di funzione. Mentre la semplice chiamata a window.alert("Hello"); è qualcosa che potresti immaginare, invece di chiamare direttamente anziché sayHello() .

Ma se ci fosse dell'altro? Hai una dozzina di posti in cui vuoi chiamare sayHello() e invece hai scritto window.alert("Hello"); . Ora vuoi che faccia un window.alert("Hello, it is now " + new Date()) . Se hai spostato tutte quelle chiamate come sayHello() , puoi cambiarle in un unico punto. Se non l'hai fatto, lo cambi in una dozzina di posti. Ciò tocca Non ripetere te stesso . Lo fai perché non vuoi doverlo fare una dozzina di volte in futuro.

Ho lavorato con una libreria i18n / l10n in passato che utilizzava funzioni per la localizzazione lato client del testo. Considera la funzione sayHello() . Puoi farlo stampare hola quando l'utente è localizzato in una lingua spagnola. Questo potrebbe sembrare qualcosa di simile:

function sayHello() {
  var language = window.navigator.userLanguage || window.navigator.language;
  if(language === 'es') { window.alert('Hola'); }
   else { window.alert("Hello"); }
}

Però, non è così che funzionava la biblioteca. Invece, aveva un set di file che assomigliava a:

# English file
greeting = hello
# Spanish file
greeting = hola

Quindi la libreria rileva le impostazioni della lingua del browser e quindi crea funzioni dinamiche con la localizzazione appropriata come valore di ritorno per una chiamata di funzione no-arguemnt basata sul file di localizzazione appropriato.

Non sono abbastanza un programmatore di Javascript per dire se è buono o cattivo ... solo che era e può essere visto come un possibile approccio.

Il punto di essere, avvolgere la chiamata a un'altra funzione in una sua funzione è spesso abbastanza utile e aiuta con la modularizzazione dell'applicazione e può anche risultare in un codice più facile da leggere.

Tutto questo a parte, stai lavorando da un tutorial. È necessario introdurre le cose il più semplicemente possibile all'inizio. L'introduzione delle chiamate di funzione stile varargs dall'inizio può risultare in un codice molto confuso per una persona che non ha familiarità con la codifica in generale. È molto più facile passare da nessun argomento, a argomenti, a stile varargs - con ogni edificio sugli esempi precedenti e comprensione.

    
risposta data 02.10.2014 - 02:56
fonte
34

Penso che sia utile a volte per nascondere l'implementazione.

 function sayHello() {
  window.alert("Hello");
 }

E questo ti dà la flessibilità di cambiarlo più tardi

 function sayHello() {
  console.log("Hello");
 }
    
risposta data 02.10.2014 - 02:19
fonte
19

Other than obfuscation are there benefits to writing something like this in real life? If so, what are the benefits?

  • centralizzazione: sebbene l'implementazione sia lunga una sola riga, se è una linea che cambia spesso, probabilmente preferisci cambiarla in un unico posto, piuttosto che dovunque venga chiamato Hello.

  • minimizzazione / occultamento delle dipendenze: il codice cliente non deve più sapere che esiste un oggetto finestra e si può persino cambiare l'intera implementazione senza influire sul codice client

  • evasione del contratto: il codice client potrebbe prevedere un modulo con una funzione sayHello. In questo caso, anche se banale, la funzione deve essere lì.

  • consistenza dei livelli di astrazione: se il codice client utilizza operazioni di alto livello, è nel tuo interesse scrivere codice client in termini di "sayHello, sayBye" e qualche altra funzione "sayXXX", invece di finestra oggetti. Infatti, nel codice cliente potresti anche non voler sapere che esiste qualcosa come un oggetto "finestra".

risposta data 02.10.2014 - 10:27
fonte
7

Incredibile che nessun'altra persona abbia menzionato il test.

La particolare linea "incartata" che hai selezionato, window.alert('hello') , è in realtà un perfetto esempio di questo. Tutto ciò che riguarda l'oggetto window è veramente veramente doloroso da testare. Moltiplicalo per 1000 volte nella tua domanda e ti garantisco che gli sviluppatori alla fine abbandoneranno i test. D'altra parte, è piuttosto semplice clobare la funzione sayHello con una spia e testare che sia stata chiamata.

Un esempio più pratico - perché in realtà chi usa effettivamente window.alert(...) nel codice di produzione? - sta controllando l'orologio di sistema. Quindi, ad esempio, questo sarebbe il wrapping di DateTime.Now in .NET, time(...) in C / C ++ o System.currentTimeMillis() in Java. davvero vuoi avvolgere quelli in una dipendenza che puoi iniettare, perché non sono (quasi) impossibili da imitare / falsificare, sono di sola lettura e non deterministici . Qualsiasi test che copra una funzione o un metodo che faccia uso diretto della funzione orologio di sistema è estremamente probabile che soffra di guasti intermittenti e / o casuali.

L'attuale wrapper è una funzione a una riga - return DateTime.Now - ma è tutto ciò che serve per prendere un oggetto mal progettato e non testabile e renderlo pulito e verificabile. È possibile sostituire un orologio falso per il wrapper e impostare il proprio tempo su ciò che si desidera. Problema risolto.

    
risposta data 03.10.2014 - 08:45
fonte
2

Come ha detto Doval, questo esempio sta probabilmente cercando di introdurti alle funzioni. Sono generale, però, è utile. Soprattutto specificando alcuni, ma non tutti, gli argomenti e passando gli altri attraverso, è possibile rendere una funzione più specifica del caso da una funzione più generale. Come esempio un po 'banale, si consideri una funzione di ordinamento che prende una matrice per ordinare e una funzione di confronto per ordinare con. Specificando una funzione di confronto che si confronta per valore numerico, posso creare una funzione sortByNumericalValue e le chiamate a quella funzione sono molto più chiare e concise.

    
risposta data 02.10.2014 - 02:10
fonte
2

Il pensiero alla base della tua domanda sembra essere: "Perché non scrivere semplicemente alert("Hello"); direttamente? È piuttosto semplice."

La risposta è, in parte, perché non vuoi davvero chiamare alert("Hello") - vuoi solo dire ciao.

Oppure: perché memorizzare i contatti sul tuo telefono, quando puoi semplicemente comporre i numeri di telefono? Perché non vuoi ricordare tutti quei numeri; perché comporre numeri è noioso e soggetto a errori; perché il numero potrebbe cambiare, ma è sempre la stessa persona all'altra estremità. Perché vuoi chiamare persone , non numeri.

Questo è ciò che si intende per termini come astrazione, indirezione, "nascondere i dettagli di implementazione" e persino "codice espressivo".

Lo stesso ragionamento si applica all'uso delle costanti invece di scrivere valori grezzi ovunque. potresti scrivere 3.141592... ogni volta che hai bisogno di π, ma per fortuna c'è Math.PI .

Potremmo anche guardare alert() se stesso. A chi importa come costruisce e mostra quella finestra di avviso? Vuoi solo avvisare l'utente. Tra la scrittura di alert("Hello") e la modifica dei pixel sul tuo schermo, c'è un profondo e profondo stack di codice e hardware, con ogni strato che racconta quello che vuole e quello successivo che si occupa dei dettagli fino a che il livello più profondo non capovolge alcuni bit nella memoria video.

Davvero non vuoi dover fare tutto da solo per dire ciao.

La programmazione - beh, qualsiasi attività, in realtà - è tutta una questione di rottura di problemi complessi in blocchi gestibili. La risoluzione di ogni blocco ti dà un blocco di base e con un numero sufficiente di elementi di base puoi creare grandi cose.

È un'algebra.

    
risposta data 05.10.2014 - 04:20
fonte
-1

È una buona idea mantenere calcolo dei valori (espressioni) separato da esecuzione di azioni (dichiarazioni). Vogliamo un controllo preciso su dove e quando verranno intraprese le azioni (come la visualizzazione dei messaggi), ma nel calcolo dei valori preferiremmo lavorare a un livello più astratto e non dovremmo preoccuparci di come quei valori sono calcolata.

Una funzione che calcola solo un valore di ritorno, usando solo gli argomenti che ha dato, è chiamata pure .

Una "funzione" che esegue un'azione è in realtà una procedura , che ha un effetto .

Qualsiasi effetto causato durante il calcolo di un valore è chiamato effetti collaterali , ed è meglio evitarli dove possibile ("Avevo solo bisogno di quella stringa, non sapevo che avrebbe martellato il banca dati! ").

Per ridurre al minimo la possibilità di effetti collaterali, dovremmo evitare di inviare troppi dati alle nostre procedure o di inserire qualsiasi calcolo al loro interno; se alcuni calcoli devono essere eseguiti in anticipo, di solito è meglio farlo separatamente in una funzione pura, quindi passare solo il risultato richiesto alla procedura. Ciò mantiene chiaro lo scopo della procedura e riduce la possibilità che possa essere riutilizzato in un secondo momento come parte di un calcolo (la funzione pura può invece essere riutilizzata).

Per lo stesso motivo, dovremmo evitare di elaborare i risultati all'interno di una procedura. È meglio restituire il risultato (se esiste) alla nostra azione ed eseguire qualsiasi elaborazione successiva con funzioni pure.

Se seguiamo queste regole, potremmo finire con una procedura come sayHello , che non ha bisogno di dati e non ha un risultato. Quindi la migliore interfaccia è di non avere argomenti e non restituire un valore. È preferibile, ad esempio, chiamare "console.log" nel mezzo di alcuni calcoli.

Per ridurre la necessità di effetti durante il calcolo, possiamo avere calcoli che restituiscono procedure ; per esempio. se dobbiamo decidere su un'azione da intraprendere, possiamo avere una funzione pura scegliere una procedura e restituirla, piuttosto che eseguirla direttamente.

Allo stesso modo, per ridurre la necessità di calcolo durante le procedure, possiamo avere procedure che prendono altre procedure come parametri (probabilmente il risultato di una funzione); per esempio. prendendo una serie di procedure e eseguendo una dopo l'altra.

    
risposta data 03.10.2014 - 01:10
fonte
-2

Direi che è una combinazione delle risposte fornite da @MichaelT e @Sleiman Jneidi.

Forse ci sono un certo numero di punti nel codice in cui si desidera salutare l'utente con un messaggio Hello, in modo tale che si comprenda quell'idea in un metodo. Nel metodo puoi tradurlo o espandere su un semplice 'Ciao' visualizzando un testo più lungo. Potresti anche voler usare una bella finestra di dialogo JQuery al posto di un avviso.

Il punto è che l'implementazione è in un unico posto. Hai solo bisogno di cambiare il codice in un unico posto. (SayHello () è forse un esempio troppo semplice)

    
risposta data 02.10.2014 - 11:59
fonte

Leggi altre domande sui tag