Qual è la convenzione JavaScript per nessuna operazione?


121

Qual è la convenzione JavaScript per nessuna operazione? Come un passcomando Python .

  • Un'opzione è semplicemente una funzione vuota: function() {}
  • offre jQuery $.noop(), che chiama semplicemente la funzione vuota sopra.
  • È accettabile inserire semplicemente un valore di falseo 0?

Nel contesto ... tutti questi funzionano senza generare errori in Chrome:

var a = 2;
(a === 1) ? alert(1) : function() {};
(a === 1) ? alert(1) : $.noop();
(a === 1) ? alert(1) : false;
(a === 1) ? alert(1) : 0;

EDIT: molte persone hanno risposto con "non farlo! Cambia la struttura del codice!" Questo mi ricorda un post in cui qualcuno chiedeva come annusare il browser. Ha ricevuto una raffica di messaggi che dicevano: "NON FARLO! È MALE", ma nessuno gli ha detto come annusare il browser . Questa non è una revisione del codice. Immagina di avere a che fare con codice legacy che non può essere modificato e senza che venga passata alcuna funzione, verrà generato un errore. O, semplicemente, è così che il cliente vuole e mi paga . Quindi, rispettosamente, rispondi alla domanda : qual è il modo migliore per specificare una funzione "nessuna operazione" in JavaScript?

EDIT2: Che ne dici di uno di questi?

true;
false;
0;
1;
null;

7
Perché non una semplice dichiarazione if?
epascarello

11
Nessuna di queste alternative 0è effettivamente migliore (o peggiore). Direi che la cosa giusta da fare è if (a === 1) doSomething();e non usare ? :quando non ha senso.
Pointy

6
Stai abusando dell'operatore ternario con un effetto collaterale. Se devi, falloif (statement) action; else ;
mplungjan

falseo 0funzionerà; nullè un bel modo per esprimere no-op.
Matt

3
Spero che il ternario abbia qualche necessità che non possiamo vedere per qualche motivo ... Sembra proprio che tu stia complicando il tuo codice per sentirti figo (l'abbiamo fatto tutti!)
Stachu

Risposte:


95

Per rispondere alla domanda originale, l'implementazione più elegante e ordinata di una funzione noop in puro Javascript (come discusso anche qui ) è Function.prototype . Questo è perché:

  1. Function.prototype è una funzione:

typeof Function.prototype === "function" // returns true

  1. Può essere richiamato come funzione e essenzialmente non fa nulla come mostrato qui:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Sebbene questo sia un "vero noop" poiché la maggior parte dei browser sembra non fare nulla per eseguire il noop definito in questo modo (e quindi salvare i cicli della CPU), potrebbero esserci alcuni problemi di prestazioni associati a questo (come menzionato anche da altri nei commenti o in altre risposte).

Tuttavia, detto questo, puoi facilmente definire la tua funzione noop e, infatti, molte librerie e framework forniscono anche funzioni noop. Di seguito sono riportati alcuni esempi:

var noop = function () {};           // Define your own noop in ES3 or ES5
const noop = () => {};               // Define in ES6 as Lambda (arrow function)
setTimeout(noop, 10000);             // Using the predefined noop

setTimeout(function () {} , 10000);  // Using directly in ES3 or ES5
setTimeout(() => {} , 10000);        // Using directly in ES6 as Lambda (arrow function)

setTimeout(angular.noop, 10000);     // Using with AngularJS 1.x
setTimeout(jQuery.noop, 10000);      // Using with jQuery

Ecco un elenco alfabetico di varie implementazioni di funzioni noop (o discussioni correlate o ricerche su Google):

AngularJS 1.x , Angular 2+ (non sembra avere un'implementazione nativa - usa la tua come mostrato sopra), Ember , jQuery , Lodash , NodeJS , Ramda , React (non sembra avere un'implementazione nativa - usa la tua come mostrato sopra), RxJS , Underscore

LINEA DI FONDO : sebbene Function.prototype sia un modo elegante per esprimere un noop in Javascript, tuttavia, potrebbero esserci alcuni problemi di prestazioni legati al suo utilizzo. Quindi, puoi definire e utilizzare il tuo (come mostrato sopra) o usarne uno definito dalla libreria / framework che potresti utilizzare nel tuo codice.


5
Questa dovrebbe essere la risposta. Si può anche usare Function.prototype()se non è necessario il timeout e si desidera che venga eseguito immediatamente.
caricato a molla il

1
setTimeout(Function(), 10000);
iegik

@iegik: +1. Sì hai ragione. Tutti i seguenti sono equivalenti: setTimeout (function () {}, 10000); OPPURE setTimeout (new Function (), 10000); OR setTimeout (Function (), 10000); O setTimeout (Funzione, 10000); poiché la grammatica Javascript e l'implementazione del costruttore di funzioni consentono questi costrutti.
Alan CS

5
In ES6 o usando babel o un altro transpiler (( )=>{};)tecnicamente puro JS e molto più corto di function () {}ma esattamente equivalente.
Ray Foss

2
Ero interessato a trovare un costrutto non operativo per disattivare in modo efficiente il codice di debug nel mio programma. In C / C ++, avrei usato le macro. Ho testato l'assegnazione del mio fn a Function.prototype e l'ho cronometrato, confrontando i risultati con il semplice fatto di avere un'istruzione if all'interno della funzione per tornare immediatamente. Li ho anche confrontati con i risultati della semplice rimozione della funzione dal ciclo. Sfortunatamente, Function.prototype non ha funzionato affatto bene. chiamare una funzione vuota era di gran lunga superiore in termini di prestazioni, anche più velocemente che chiamare la funzione con il semplice test "if" all'interno per tornare.
bearvarine

73

Più conciso e noop performante è una funzione freccia vuota : ()=>{}.

Le funzioni Arrow funzionano in modo nativo in tutti i browser tranne IE (c'è una trasformazione babel se necessario): MDN


()=>{} vs. Function.Prototype

  • ()=>{}è l' 87% più veloce rispetto Function.prototypea Chrome 67.
  • ()=>{}è del 25% più veloce rispetto Function.prototypea Firefox 60.
  • ()=>{}è dell'85% più veloce rispetto Function.prototypea Edge (15/6/2018) .
  • ()=>{}è il 65% in meno di codice rispetto a Function.prototype.

Il test seguente si riscalda utilizzando la funzione freccia per dare un bias Function.prototype, ma la funzione freccia è il chiaro vincitore:

const noop = ()=>{};
const noopProto = Function.prototype;

function test (_noop, iterations) {
    const before = performance.now();
    for(let i = 0; i < iterations; i++) _noop();
    const after = performance.now();
    const elapsed = after - before;
    console.info(`${elapsed.toFixed(4)}MS\t${_noop.toString().replace('\n', '')}\tISNOOP? ${_noop() === undefined}`);
    return elapsed;
}

const iterations = 10000000
console.info(`noop time for ${iterations.toLocaleString()} iterations`)
const timings = {
    noop: test(noop, iterations),
    noopProto: test(noopProto, iterations)
}

const percentFaster = ((timings.noopProto - timings.noop)/timings.noopProto).toLocaleString("en-us", { style: "percent" });
console.info(`()=>{} is ${percentFaster} faster than Function.prototype in the current browser!`)


1
Ho creato un test jsPerf per confrontare alcune opzioni: noop-function . Sembra che in Firefox 54 tutte le alternative sembrino quasi equivalenti; in Chromium 58, Function.prototypeè drasticamente più lento, ma nessuna delle altre opzioni ha un netto vantaggio.
Lucas Werkmeister,

_=>{}è un carattere in meno e fa la stessa cosa.
Ross Attrill

@RossAttrill * cosa simile - _=>{}ha un singolo parametro. Se qualcuno utilizza TypeScript con una configurazione ragionevolmente rigida, non verrà compilato. Se lo chiami, il tuo IDE probabilmente ti dirà che accetta un singolo parametro che può essere di qualsiasi tipo (sia JavaScript che in particolare TypeScript in vscode).
cchamberlain

15

tutto ciò che tendi a ottenere qui è sbagliato. Le espressioni ternarie non devono essere utilizzate come una dichiarazione completa, solo nell'espressione, quindi la risposta alla tua domanda è:

nessuno dei tuoi suggerimenti, invece:

var a = 2;
if (a === 1)
    alert(1)
// else do nothing!

quindi il codice è facilmente comprensibile, leggibile e quanto più efficiente possibile.

Perché renderlo più difficile, quando può essere semplice?

modificare:

Quindi, un comando "nessuna operazione" indica fondamentalmente una struttura di codice inferiore?

Stai perdendo il mio punto. Tutto quanto sopra riguarda l'espressione ternaria x ? y : z.

Tuttavia, un comando senza operazione non ha senso in linguaggi di livello superiore come Javascript.

Di solito è usato, in linguaggi di livello inferiore come assembly o C, come un modo per fare in modo che il processore non faccia nulla per un'istruzione per scopi di temporizzazione.

In JS, se fare 0;, null;, function () {};o una dichiarazione di vuoto, ci sono grandi possibilità che esso sarà ignorato dal interprete quando si sta leggendo, ma prima che venga interpretata, quindi alla fine, devi semplicemente rendere il vostro programma di essere caricati più lentamente per un tempo davvero minimo. Nota Bene : lo presumo, poiché non sono coinvolto in alcun interprete JS ampiamente utilizzato e ci sono possibilità che ogni interprete abbia la propria strategia.

Nel caso in cui usi qualcosa di un po 'più complicato, come $.noop()o var foo = function () {}; foo(), l'interprete potrebbe eseguire una chiamata di funzione inutile che finirà per rovinare alcuni byte del tuo stack di funzioni e alcuni cicli.

L'unico motivo per cui vedo una funzione come $.noop()potrebbe esistere, sarebbe essere in grado di dare ancora una funzione di callback a qualche funzione di evento che genererebbe un'eccezione se non può chiamare quella callback. Ma poi, è necessariamente una funzione che devi dare, e dargli il noopnome è una buona idea, quindi stai dicendo ai tuoi lettori (e potresti essere tu tra 6 mesi) che dai di proposito una funzione vuota.

Alla fine, non esiste una struttura del codice "inferiore" o "superiore". Hai ragione o torto nel modo in cui usi i tuoi strumenti. Usare un ternario per il tuo esempio è come usare un martello quando vuoi avvitare. Funzionerà, ma non sei sicuro di poter appendere qualcosa a quella vite.

Ciò che potrebbe essere considerato "inferiore" o "superiore" è l'algoritmo e le idee che inserisci nel codice. Ma questa è un'altra cosa.


1
Quindi, un comando "nessuna operazione" indica fondamentalmente una struttura di codice inferiore?
kmiklas

3
@kmiklas: non posso dire di aver mai trovato un legittimo bisogno di un NOOP, al di fuori dell'assembler.
Matt Burland

@zmo: capisco il tuo punto di vista riguardo a come i tuoi commenti si riferiscono all'espressione ternaria; tutti sembrano aver perso il mio punto che questo era solo un esempio illustrativo di una chiamata alla funzione "Nessuna operazione".
kmiklas

1
Ovviamente ci sono motivi per volere / aver bisogno di una funzione non operativa. Non fare generalizzazioni generali basate sui tuoi 12 secondi di pensiero profondo su qualcosa. JavaScript è un linguaggio che rende le funzioni completamente controllabili come variabili. Supponi di aver bisogno di disabilitare una funzione senza un test esplicito? Questo sarebbe perfetto per quello. Se hai una funzione che appare frequentemente, come un'istruzione di debug, sarebbe bello poterla disattivare riassegnando la funzione a no-op piuttosto che dover aggiungere codice extra per testare qualche variabile ogni volta che la funzione appare .
bearvarine

2
@bearvarine grazie per l'alta opinione che hai di me MrGreen. Hai perfettamente ragione nel tuo commento, ma non è proprio per la progettazione del codice, solo per la progettazione di prototipi utilizzando un hack. Quello che descrivi è anche chiamato patch delle scimmie, e c'è una ragione per questo ;-)
zmo

7

Penso che jQuery noop()sia principalmente inteso a prevenire il crash del codice fornendo una funzione predefinita quando quella richiesta non è disponibile. Ad esempio, considerando il seguente esempio di codice, $.noopviene scelto se fakeFunctionnon è definito, impedendo l' fnarresto anomalo della chiamata successiva a :

var fn = fakeFunction || $.noop;
fn() // no crash

Quindi, noop()consente di risparmiare memoria evitando di scrivere la stessa funzione vuota più volte ovunque nel codice. A proposito, $.noopè un po 'più corto di function(){}(6 byte salvati per token). Quindi, non esiste alcuna relazione tra il codice e il modello di funzione vuoto. Usa null, falseo 0se vuoi, nel tuo caso non ci saranno effetti collaterali. Inoltre, vale la pena notare che questo codice ...

true/false ? alert('boo') : function(){};

... è completamente inutile dato che non chiamerai mai la funzione, e questa ...

true/false ? alert('boo') : $.noop();

... è ancora più inutile dato che chiami una funzione vuota, che è esattamente la stessa di ...

true/false ? alert('boo') : undefined;

Sostituiamo l'espressione ternaria con ifun'affermazione per vedere quanto è inutile:

if (true/false) {
    alert('boo');
} else {
    $.noop(); // returns undefined which goes nowhere
}

Potresti semplicemente scrivere:

if (true/false) alert('boo');

O anche più breve:

true/false && alert('boo');

Per rispondere finalmente alla tua domanda, immagino che una "operazione non convenzionale" sia quella che non viene mai scritta.


1
Tuttavia a volte è necessario fornire una funzione. Ad esempio con le promesse (fn, fn) a volte si desidera fornire la seconda funzione ma non la prima funzione. quindi hai bisogno di qualcosa per un segnaposto ...mypromise.then($.noop, myErrorhandler);
John Henckel

3

Io uso:

 (0); // nop

Per testare il tempo di esecuzione di questa esecuzione come:

console.time("mark");
(0); // nop
console.timeEnd("mark");

risultato: voto: 0.000ms

L'utilizzo Boolean( 10 > 9)può essere ridotto a semplicemente ( 10 > 9)che ritorna true. Venendo all'idea di usare un singolo operando, mi aspettavo che (0);sarebbe tornato false, ma restituisce semplicemente l'argomento come può essere rivisto eseguendo questo test sulla console.

> var a = (0);
< undefined
> a
< 0

1
molti che tentano questo otterrannoargument 0 is not a function
Code Whisperer

4
Stai semplicemente assegnando 0. IMO noopdovrebbe essere una funzione che valuta con il undefinedrisultato.
cchamberlain

1
Com'è questa affermazione (0); assegnando uno 0 ?, dove sono var e segno di uguale? Non c'è un nome di funzione davanti allo (0), quindi non vedo come potrebbe essere un argomento? se provi a digitare ((0)), torna come numero. Quando rispondo alla domanda, fornivo un'affermazione che uso per imitare un NOP, ma sono disposto a cambiare la mia risposta per usarla semplicemente; per rappresentare una dichiarazione vuota
Uova

1
Penso (0); è una soluzione accettabile alla domanda di OP. Penso che le persone si stiano confondendo perché hanno trovato questa pagina mentre cercavano una funzione che non fa nulla, piuttosto che un'istruzione che non fa nulla. L'OP non aiuta inizialmente suggerendo function(){}come soluzione. La chiamata (0)()causeràTypeError: 0 is not a function
Benjamin

Mi riferivo var a = (0);. Un no-op non dovrebbe cambiare la memoria e il tuo esempio di assegnazione fa proprio questo. Il (0)da solo può essere considerato un inutile no-op (ce ne sono un numero infinito in JavaScript, quindi non c'è nulla che renda speciale il tuo esempio qui).
cchamberlain,

2

Non c'è assolutamente alcun problema o penalizzazione delle prestazioni dell'utilizzo di Function.prototypeover () => {}.

Il vantaggio principale di Function.prototypeè avere una funzione singleton piuttosto che ridefinire ogni volta una nuova funzione anonima. È particolarmente importante utilizzare una no-op come Function.prototypequando si definiscono i valori predefiniti e si memorizza in quanto fornisce un puntatore a un oggetto coerente che non cambia mai.

Il motivo per cui raccomando Function.prototypepiuttosto che Functionè perché non sono la stessa cosa:

Function() === Function()
// false

Function.prototype() === Function.prototype()
// true

Inoltre, i benchmark di altre risposte sono fuorvianti . In effetti, Function.prototypefunziona più velocemente che a () => {}seconda di come scrivi ed esegui il benchmark:

Non ci si può fidare dei benchmark JS << Chiamando specificatamente benchmark su questa domanda.

Non applicare lo stile al codice dai benchmark; fare tutto ciò che è gestibile e lasciare che l'interprete capisca come ottimizzare a lungo termine.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.