Was ist die JavaScript-Konvention für keine Operation?

121

Was ist die JavaScript-Konvention für keine Operation? Wie ein Python- passBefehl.

  • Eine Option ist einfach eine leere Funktion: function() {}
  • jQuery bietet an $.noop(), die einfach die obige leere Funktion aufruft.
  • Ist es akzeptabel, einfach einen Wert von falseoder einzugeben 0?

Im Kontext ... all dies funktioniert ohne einen Fehler in Chrome auszulösen:

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

EDIT: Viele Leute antworteten mit: "Tu das nicht! Ändere die Codestruktur!" Dies erinnert mich an einen Beitrag, in dem jemand gefragt hat, wie man den Browser schnüffelt. Er erhielt eine Flut von Posts mit der Aufschrift "TUN SIE DAS NICHT! ES IST BÖSE", aber niemand sagte ihm, wie man am Browser schnüffelt . Dies ist keine Codeüberprüfung. Stellen Sie sich vor, Sie haben es mit Legacy-Code zu tun, der nicht geändert werden kann, und ohne eine übergebene Funktion wird ein Fehler ausgegeben. Oder einfach, so will es der Kunde und er bezahlt mich . Beantworten Sie daher respektvoll die Frage : Wie kann eine Funktion "keine Operation" in JavaScript am besten angegeben werden?

EDIT2: Wie wäre es mit einem davon?

true;
false;
0;
1;
null;
kmiklas
quelle
7
Warum nicht eine einfache if-Anweisung?
Epascarello
11
Keine dieser Alternativen 0ist effektiv besser (oder schlechter). Ich würde sagen, das Richtige ist, es if (a === 1) doSomething();nicht zu verwenden, ? :wenn es keinen Sinn ergibt.
Pointy
6
Sie missbrauchen den ternären Operator mit einem Nebeneffekt. Wenn Sie müssen, tun Sieif (statement) action; else ;
mplungjan
Ja falseoder 0wird funktionieren; nullist eine gute Möglichkeit, No-Op auszudrücken.
Matt
3
Ich hoffe, der Ternär hat eine Notwendigkeit, die wir aus irgendeinem Grund nicht sehen können ... Es sieht so aus, als würden Sie Ihren Code komplizieren, um sich cool zu fühlen (wir haben es alle geschafft!)
Stachu

Antworten:

95

Um die ursprüngliche Frage zu beantworten, ist Function.prototype die eleganteste und sauberste Implementierung einer Noop-Funktion in reinem Javascript (wie auch hier erläutert ) . Das ist weil:

  1. Function.prototype ist eine Funktion:

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

  1. Es kann als Funktion aufgerufen werden und führt im Wesentlichen nichts aus, wie hier gezeigt:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Obwohl dies ein "echtes Noop" ist, da die meisten Browser anscheinend nichts tun, um das auf diese Weise definierte Noop auszuführen (und damit CPU-Zyklen zu sparen), kann dies zu Leistungsproblemen führen (wie auch von anderen in Kommentaren oder in erwähnt) Andere Antwort).

Allerdings können Sie leicht Ihre eigene Noop-Funktion definieren, und tatsächlich bieten viele Bibliotheken und Frameworks auch Noop-Funktionen. Nachfolgend einige Beispiele:

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

Hier ist eine alphabetische Liste verschiedener Implementierungen von Noop-Funktionen (oder verwandten Diskussionen oder Google-Suchen):

AngularJS 1.x , Angular 2+ (scheint keine native Implementierung zu haben - verwenden Sie Ihre eigene wie oben gezeigt), Ember , jQuery , Lodash , NodeJS , Ramda , React (scheint keine native Implementierung zu haben - verwenden Sie Ihre eigene wie oben gezeigt), RxJS , Unterstrich

BOTTOM LINE : Obwohl Function.prototype eine elegante Möglichkeit ist, ein Noop in Javascript auszudrücken, kann es im Zusammenhang mit seiner Verwendung zu Leistungsproblemen kommen. Sie können also Ihre eigenen definieren und verwenden (wie oben gezeigt) oder eine verwenden, die von der Bibliothek / dem Framework definiert wird, die Sie möglicherweise in Ihrem Code verwenden.

Alan CS
quelle
5
Dies sollte die Antwort sein. Man kann es sogar verwenden, Function.prototype()wenn Sie das Timeout nicht benötigen und möchten, dass es sofort ausgeführt wird.
Springloaded
1
setTimeout(Function(), 10000);
iegik
@iegik: +1. Ja du hast Recht. Alle folgenden Angaben sind gleichwertig: setTimeout (function () {}, 10000); ODER setTimeout (neue Funktion (), 10000); ODER setTimeout (Funktion (), 10000); ODER setTimeout (Funktion, 10000); da die Javascript-Grammatik und die Implementierung des Funktionskonstruktors diese Konstrukte zulassen.
Alan CS
5
In ES6 oder mit Babel oder einem anderen Transpiler (( )=>{};)technisch Pure JS und viel kürzer als function () {}aber genau gleichwertig.
Ray Foss
2
Ich war daran interessiert, ein No-Op-ähnliches Konstrukt zu finden, um den Debug-Code in meinem Programm effizient zu deaktivieren. In C / C ++ hätte ich Makros verwendet. Ich habe getestet, wie ich mein fn Function.prototype zugewiesen habe, und habe es zeitlich festgelegt. Dabei habe ich die Ergebnisse mit einer if-Anweisung in der Funktion verglichen, die sofort zurückgegeben werden soll. Ich habe diese auch mit den Ergebnissen verglichen, bei denen die Funktion einfach ganz aus der Schleife entfernt wurde. Leider hat Function.prototype überhaupt keine gute Leistung erbracht. Das Aufrufen einer leeren Funktion war in der Leistung weit überlegen, sogar schneller als das Aufrufen der Funktion mit dem einfachen "Wenn" -Test im Inneren, um zurückzukehren.
Bearvarine
72

Das prägnanteste und performanteste Noop ist eine leere Pfeilfunktion : ()=>{}.

Pfeilfunktionen funktionieren nativ in allen Browsern außer IE (es gibt eine Babel-Transformation, wenn Sie müssen): MDN


()=>{} vs. Function.Prototype

  • ()=>{}ist 87% schneller als Function.prototypein Chrome 67.
  • ()=>{} ist 25% schneller als Function.prototypein Firefox 60.
  • ()=>{}ist 85% schneller als Function.prototypein Edge (15.06.2008) .
  • ()=>{} ist 65% weniger Code als Function.prototype.

Der folgende Test wird mithilfe der Pfeilfunktion aufgeheizt, um eine Verzerrung zu Function.prototypeerzielen. Die Pfeilfunktion ist jedoch der klare Gewinner:

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!`)

Kammerherr
quelle
1
Ich habe einen jsPerf-Test erstellt, um einige Optionen zu vergleichen: noop-function . Es scheint, dass in Firefox 54 alle Alternativen ungefähr gleichwertig sind; in Chrom 58 Function.prototypeist drastisch langsamer, aber keine der anderen Optionen hat einen eindeutigen Vorteil.
Lucas Werkmeister
_=>{}ist ein Zeichen weniger und macht das Gleiche.
Ross Attrill
@ RossAttrill * ähnliche Sache - _=>{}hat einen einzelnen Parameter. Wenn jemand TypeScript mit einer relativ strengen Konfiguration verwendet, wird dies nicht kompiliert. Wenn Sie es aufrufen, wird Ihre IDE Ihnen wahrscheinlich mitteilen, dass es einen einzelnen Parameter akzeptiert, der von einem beliebigen Typ sein kann (sowohl JavaScript als auch insbesondere TypeScript in vscode).
Cchamberlain
15

Was immer Sie hier erreichen wollen, ist falsch. Ternäre Ausdrücke sollen nicht als vollständige Aussage verwendet nur als Ausdruck. Die Antwort auf Ihre Frage lautet daher:

Keiner Ihrer Vorschläge, stattdessen:

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

dann ist der Code leicht verständlich, lesbar und so effizient wie möglich.

Warum es schwieriger machen, wenn es einfach sein kann?

bearbeiten:

Zeigt ein Befehl "keine Operation" im Grunde genommen eine minderwertige Codestruktur an?

Du vermisst meinen Standpunkt. Bei alledem geht es um den ternären Ausdruck x ? y : z.

In höheren Sprachen wie Javascript ist ein Befehl no operation jedoch nicht sinnvoll.

Es wird normalerweise in untergeordneten Sprachen wie Assembly oder C verwendet, um den Prozessor zu veranlassen, für Timing-Zwecke nichts für einen Befehl zu tun.

In JS, ob Sie tun 0;, null;, function () {};oder eine leere Aussage, gibt es große Chancen , dass es durch die interpretor ignoriert wird, wenn er sie liest, aber bevor es, so dass am Ende interpretiert wird, müssen Sie nur Ihr Programm machen sein langsamer geladen durch eine wirklich winzige Zeitspanne. Nota Bene : Ich gehe davon aus, da ich an keinem weit verbreiteten JS-Interpreter beteiligt bin und es Chancen gibt, dass jeder Interpreter seine eigene Strategie hat.

Wenn Sie etwas Komplizierteres wie $.noop()oder verwenden var foo = function () {}; foo(), führt der Interpreter möglicherweise einen nicht nützlichen Funktionsaufruf aus, der einige Bytes Ihres Funktionsstapels und einige Zyklen beeinträchtigt.

Der einzige Grund, warum ich eine Funktion sehe, wie $.noop()sie existieren würde, wäre, einer Ereignisfunktion, die eine Ausnahme auslösen würde, wenn sie diesen Rückruf nicht aufrufen kann, weiterhin eine Rückruffunktion geben zu können. Aber dann ist es notwendigerweise eine Funktion, die Sie geben müssen, und geben Sie ihr dienoop ist eine gute Idee Namen damit Sie Ihren Lesern (und das können Sie in 6 Monaten sein) sagen, dass Sie absichtlich eine leere Funktion geben.

Am Ende gibt es keine "minderwertige" oder "überlegene" Codestruktur. Sie haben entweder Recht oder Unrecht in der Art und Weise, wie Sie Ihre Werkzeuge verwenden. Die Verwendung eines Ternärs für Ihr Beispiel ist wie die Verwendung eines Hammers, wenn Sie schrauben möchten. Es wird funktionieren, aber Sie sind sich nicht sicher, ob Sie etwas an diese Schraube hängen können.

Was als "minderwertig" oder "überlegen" angesehen werden kann, ist der Algorithmus und die Ideen, die Sie in Ihren Code einfügen. Aber das ist eine andere Sache.

zmo
quelle
1
Zeigt ein Befehl "keine Operation" im Grunde genommen eine minderwertige Codestruktur an?
kmiklas
3
@kmiklas: Ich kann nicht sagen, dass ich jemals einen legitimen Bedarf an einem NOOP außerhalb des Assemblers gefunden habe.
Matt Burland
@zmo: Ich verstehe Ihren Standpunkt bezüglich der Beziehung Ihrer Kommentare zum ternären Ausdruck. Jeder scheint meinen Standpunkt verfehlt zu haben, dass dies nur ein anschauliches Beispiel für einen Aufruf der Funktion "Keine Operation" war.
kmiklas
1
Natürlich gibt es Gründe, eine No-Op-Funktion zu wollen / brauchen. Machen Sie keine umfassenden Verallgemeinerungen, die auf Ihren 12 Sekunden tiefem Nachdenken über etwas basieren. JavaScript ist eine Sprache, mit der Funktionen als Variablen vollständig gesteuert werden können. Angenommen, Sie müssen eine Funktion ohne expliziten Test deaktivieren? Das wäre perfekt dafür. Wenn Sie eine Funktion haben, die häufig angezeigt wird, z. B. eine Debug-Anweisung, ist es hilfreich, sie durch erneutes Zuweisen der Funktion zu no-op auszuschalten, anstatt bei jedem Auftreten der Funktion zusätzlichen Code hinzufügen zu müssen, um eine Variable zu testen .
Bearvarine
2
@bearvarine danke für die hohe Meinung, die Sie von mir haben :-D. Sie haben absolut Recht in Ihrem Kommentar, aber es ist nicht wirklich für das Code-Design, sondern nur für das Mockup-Design mit einem Hack. Was du beschreibst, wird auch Affen-Patching genannt, und dafür gibt es einen Grund
;-)
7

Ich denke, jQuery noop()soll hauptsächlich verhindern, dass Code abstürzt, indem eine Standardfunktion bereitgestellt wird, wenn die angeforderte nicht verfügbar ist. Unter Berücksichtigung des folgenden Codebeispiels $.noopwird beispielsweise ausgewählt, wenn fakeFunctiones nicht definiert ist, um zu verhindern, dass der nächste Aufruf fnvon abstürzt:

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

Dann noop()können Speicher sparen , indem die Vermeidung der gleichen leeren Funktion mehrere Male überall in Ihrem Code zu schreiben. Ist übrigens $.noopetwas kürzer als function(){}(6 Bytes pro Token gespeichert). Es gibt also keine Beziehung zwischen Ihrem Code und dem leeren Funktionsmuster. Verwenden Sie null, falseoder 0wenn Sie in Ihrem Fall mögen, wird es keine Nebenwirkung sein. Darüber hinaus ist es erwähnenswert, dass dieser Code ...

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

... ist völlig nutzlos, da Sie die Funktion niemals aufrufen werden, und diese ...

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

... ist noch nutzloser, da Sie eine leere Funktion aufrufen, die genau das gleiche ist wie ...

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

Ersetzen wir den ternären Ausdruck durch eine ifAussage, um zu sehen, wie nutzlos er ist:

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

Sie könnten einfach schreiben:

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

Oder noch kürzer:

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

Um Ihre Frage endgültig zu beantworten, denke ich, dass eine "konventionelle No-Operation" diejenige ist, die niemals geschrieben wird.

Blatt
quelle
1
Manchmal muss man jedoch eine Funktion bereitstellen. Zum Beispiel mit Versprechungen dann (fn, fn) möchten Sie manchmal die zweite Funktion bereitstellen, aber nicht die erste Funktion. Deshalb brauchen Sie etwas für einen Platzhalter ...mypromise.then($.noop, myErrorhandler);
John Henckel
3

Ich benutze:

 (0); // nop

So testen Sie die Ausführungszeit dieses Laufs wie folgt:

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

Ergebnis: Marke: 0,000ms

Die Verwendung Boolean( 10 > 9)kann auf einfach reduziert werden, ( 10 > 9)was zurückgibt true. Die Idee, einen einzelnen Operanden zu verwenden, den ich voll und ganz erwartet hatte, (0);würde zurückkehren false, aber das Argument wird einfach zurückgegeben, wie durch Ausführen dieses Tests an der Konsole überprüft werden kann.

> var a = (0);
< undefined
> a
< 0
Eier
quelle
1
Viele, die dies versuchen, werdenargument 0 is not a function
Code Whisperer
4
Sie weisen einfach 0 zu. IMO noopsollte eine Funktion sein, die mit dem undefinedErgebnis ausgewertet wird .
Kammerherr
1
Wie ist diese Aussage (0); Zuweisung einer 0?, wo ist var und Gleichheitszeichen? Vor (0) steht kein Funktionsname, daher sehe ich nicht, wie dies ein Argument sein könnte. Wenn Sie typeof ((0)) versuchen, wird es als Zahl zurückgegeben. Als ich die Frage beantwortete, gab ich eine Erklärung ab, mit der ich einen NOP imitiere, aber ich bin bereit, meine Antwort so zu ändern, dass sie einfach verwendet wird. eine leere Aussage darstellen
Eier
1
Ich denke (0); ist eine akzeptable Lösung für die Frage von OP. Ich denke, die Leute sind verwirrt, weil sie diese Seite gefunden haben, als sie nach einer Funktion gesucht haben, die nichts tut, anstatt nach einer Aussage, die nichts tut. Das OP hilft nicht, indem es zunächst function(){}eine Lösung vorschlägt . Anruf (0)()wird verursachenTypeError: 0 is not a function
Benjamin
Ich bezog mich auf var a = (0);. Ein No-Op sollte den Speicher nicht ändern, und Ihr Zuweisungsbeispiel macht genau das. Das (0)allein kann als nutzloses No-Op angesehen werden (es gibt unendlich viele davon in JavaScript, daher gibt es nichts, was Ihr Beispiel hier besonders macht).
Cchamberlain
2

Es gibt absolut kein Problem oder Leistungseinbußen bei der Verwendung von Function.prototypeOver () => {}.

Der Hauptvorteil Function.prototypebesteht darin, eine Singleton-Funktion zu haben, anstatt jedes Mal eine neue anonyme Funktion neu zu definieren. Es ist besonders wichtig, ein No-Op wie Function.prototypebeim Definieren von Standardwerten und beim Speichern zu verwenden, da Sie einen konsistenten Objektzeiger erhalten, der sich nie ändert.

Den Grund empfehle ich Function.prototype eher als, Functionist, dass sie nicht gleich sind:

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

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

Ebenfalls, Benchmarks aus anderen Antworten sind irreführend . Tatsächlich ist Function.prototypedie Leistung schneller als () => {}je nachdem, wie Sie den Benchmark schreiben und ausführen:

Sie können JS-Benchmarks nicht vertrauen. << Speziell Benchmarks für diese Frage aufrufen.

Gestalten Sie Ihren Code nicht anhand von Benchmarks. Tun Sie alles, was wartbar ist, und lassen Sie den Dolmetscher herausfinden, wie er langfristig optimieren kann.

Sawtaytoes
quelle