Quelle est la convention JavaScript pour aucune opération?

121

Quelle est la convention JavaScript pour aucune opération? Comme une passcommande Python .

  • Une option est simplement une fonction vide: function() {}
  • jQuery propose $.noop(), qui appelle simplement la fonction vide ci-dessus.
  • Est-il acceptable d'entrer simplement une valeur de falseou 0?

Dans le contexte ... tout cela fonctionne sans générer d'erreur dans 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: Beaucoup de gens ont répondu: "Ne faites pas ça! Changez la structure du code!" Cela me rappelle un article où quelqu'un a demandé comment renifler le navigateur. Il a reçu une avalanche de messages disant: "NE FAITES PAS CELA! C'EST MAUVAIS", mais personne ne lui a dit comment renifler le navigateur . Ce n'est pas une révision de code. Imaginez que vous avez affaire à du code hérité qui ne peut pas être modifié, et sans une fonction transmise, il lancera une erreur. Ou, tout simplement, c'est ainsi que le client le souhaite et il me paie . Donc, respectueusement, veuillez répondre à la question : Quelle est la meilleure façon de spécifier une fonction «sans opération» en JavaScript?

EDIT2: Que diriez-vous de l'un d'entre eux?

true;
false;
0;
1;
null;
kmiklas
la source
7
Pourquoi pas une simple déclaration if?
epascarello
11
Aucune de ces alternatives 0n'est effectivement meilleure (ou pire). Je dirais que la bonne chose à faire est de if (a === 1) doSomething();ne pas utiliser ? :lorsque cela n'a pas de sens.
Pointy
6
Vous abusez de l'opérateur ternaire avec un effet secondaire. Si vous devez, faitesif (statement) action; else ;
mplungjan
Oui falseou 0fonctionnera; nullest une belle façon d'exprimer le no-op.
Matt
3
J'espère que le ternaire a une certaine nécessité que nous ne pouvons pas voir pour une raison quelconque ... On dirait que vous compliquez votre code pour vous sentir cool (nous l'avons tous fait!)
Stachu

Réponses:

95

Pour répondre à la question originale, l'implémentation la plus élégante et la plus soignée d'une fonction noop en Javascript pur (comme cela est également discuté ici ) est Function.prototype . Ceci est dû au fait:

  1. Function.prototype est une fonction:

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

  1. Il peut être appelé en tant que fonction et ne fait essentiellement rien comme indiqué ici:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Bien que ce soit un "vrai noop" puisque la plupart des navigateurs semblent ne rien faire pour exécuter le noop défini de cette façon (et donc économiser les cycles CPU), il peut y avoir des problèmes de performances associés à cela (comme cela est également mentionné par d'autres dans les commentaires ou dans autres réponses).

Cependant, cela étant dit, vous pouvez facilement définir votre propre fonction noop et, en fait, de nombreuses bibliothèques et frameworks fournissent également des fonctions noop. Voici quelques exemples:

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

Voici une liste alphabétique des différentes implémentations des fonctions noop (ou des discussions associées ou des recherches Google):

AngularJS 1.x , Angular 2+ (ne semble pas avoir d'implémentation native - utilisez la vôtre comme indiqué ci-dessus), Ember , jQuery , Lodash , NodeJS , Ramda , React (ne semble pas avoir d'implémentation native - utilisez la vôtre comme indiqué ci-dessus), RxJS , Underscore

BOTTOM LINE : Bien que Function.prototype soit une manière élégante d'exprimer un noop en Javascript, cependant, il peut y avoir des problèmes de performances liés à son utilisation. Ainsi, vous pouvez définir et utiliser le vôtre (comme indiqué ci-dessus) ou en utiliser un défini par la bibliothèque / le framework que vous pourriez utiliser dans votre code.

Alan CS
la source
5
Cela devrait être la réponse. On peut même l'utiliser Function.prototype()si vous n'avez pas besoin du délai et que vous voulez qu'il s'exécute immédiatement.
ressort
1
setTimeout(Function(), 10000);
iegik
@iegik: +1. Oui vous avez raison. Tous les éléments suivants sont équivalents: setTimeout (function () {}, 10000); OU setTimeout (nouvelle fonction (), 10000); OU setTimeout (fonction (), 10000); OU setTimeout (Fonction, 10000); puisque la grammaire Javascript et l'implémentation du constructeur Function autorisent ces constructions.
Alan CS
5
En ES6 ou en utilisant babel ou un autre transpiler (( )=>{};)techniquement Pure JS et beaucoup plus court que function () {}mais exactement équivalent.
Ray Foss
2
J'étais intéressé par la recherche d'une construction de type no-op pour désactiver efficacement le code de débogage dans mon programme. En C / C ++, j'aurais utilisé des macros. J'ai testé l'affectation de mon fn à Function.prototype et je l'ai chronométré, en comparant les résultats à une simple instruction if à l'intérieur de la fonction à renvoyer immédiatement. J'ai également comparé ceux-ci aux résultats de la simple suppression de la fonction de la boucle. Malheureusement, Function.prototype n'a pas du tout bien fonctionné. appeler une fonction vide était bien supérieur en performances, encore plus rapide que d'appeler la fonction avec le simple test «if» à l'intérieur pour retourner.
bearvarine
73

Le plus concis et noop est une performante fonction vide flèche : ()=>{}.

Les fonctions fléchées fonctionnent nativement dans tous les navigateurs sauf IE (il y a une transformation babel si vous devez): MDN


()=>{} contre. Function.Prototype

  • ()=>{}est 87% plus rapide que Function.prototypedans Chrome 67.
  • ()=>{}est 25% plus rapide que Function.prototypedans Firefox 60.
  • ()=>{}est 85% plus rapide que Function.prototypedans Edge (15/06/2018) .
  • ()=>{}est 65% moins de code que Function.prototype.

Le test ci-dessous se réchauffe en utilisant la fonction de flèche pour donner un biais Function.prototype, mais la fonction de flèche est clairement gagnante:

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

cchamberlain
la source
1
J'ai créé un test jsPerf pour comparer certaines options: noop-function . Il semble que dans Firefox 54, toutes les alternatives semblent être à peu près équivalentes; dans Chromium 58, Function.prototypeest considérablement plus lent, mais aucune des autres options ne présente un avantage certain.
Lucas Werkmeister
_=>{}est un caractère de moins et fait la même chose.
Ross Attrill le
@RossAttrill * chose similaire - _=>{}a un seul paramètre. Si quelqu'un utilise TypeScript avec une configuration raisonnablement stricte, cela ne compilerait pas. Si vous l'appelez, votre IDE vous dira probablement qu'il accepte un seul paramètre qui peut être de n'importe quel type (à la fois JavaScript et surtout TypeScript dans vscode).
cchamberlain
15

tout ce que vous avez tendance à réaliser ici est faux. Les expressions ternaires ne doivent pas être utilisées comme une déclaration complète, seulement dans l'expression, donc la réponse à votre question est:

aucune de vos suggestions, faites plutôt:

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

alors le code est facilement compréhensible, lisible et aussi efficace que possible.

Pourquoi rendre cela plus difficile, alors que cela peut être simple?

Éditer:

Alors, une commande "no-operation" indique-t-elle fondamentalement une structure de code inférieure?

Vous manquez mon point. Tout ce qui précède concerne l'expression ternaire x ? y : z.

Mais, une commande sans opération n'a pas de sens dans les langages de niveau supérieur tels que Javascript.

Il est généralement utilisé, dans des langages de niveau inférieur tels que l'assembly ou C, pour que le processeur ne fasse rien pour une instruction à des fins de synchronisation.

Dans JS, si vous le faites 0;, null;, function () {};ou une déclaration vide, il y a de grandes chances qu'il sera ignoré par l'interprète quand il est en train de lire, mais avant qu'il est interprété, donc à la fin, vous allez juste faire votre programme soit chargé plus lentement par une très petite quantité de temps. Nota Bene : Je suppose cela, car je ne suis impliqué dans aucun interpréteur JS largement utilisé, et il y a des chances que chaque interprète ait sa propre stratégie.

Si vous utilisez quelque chose d'un peu plus compliqué, comme $.noop()ou var foo = function () {}; foo(), alors l'interpréteur peut faire un appel de fonction inutile qui finira par gâcher quelques octets de votre pile de fonctions, et quelques cycles.

La seule raison pour laquelle je vois une fonction telle $.noop()qu'elle existerait, serait de pouvoir toujours donner une fonction de rappel à une fonction d'événement qui lèverait une exception si elle ne peut pas appeler ce rappel. Mais alors, c'est forcément une fonction que vous devez donner, et lui donner le noopnom est une bonne idée donc vous dites à vos lecteurs (et cela peut être vous dans 6 mois) que vous donnez volontairement une fonction vide.

En fin de compte, il n'y a pas de structure de code «inférieure» ou «supérieure». Vous avez raison ou tort dans la façon dont vous utilisez vos outils. Utiliser un ternaire pour votre exemple, c'est comme utiliser un marteau lorsque vous voulez visser. Cela fonctionnera, mais vous n'êtes pas sûr de pouvoir accrocher quelque chose à cette vis.

Ce qui peut être considéré comme "inférieur" ou "supérieur" est l'algorithme et les idées que vous mettez dans votre code. Mais c'est autre chose.

zmo
la source
1
Alors, une commande "no-operation" indique-t-elle fondamentalement une structure de code inférieure?
kmiklas
3
@kmiklas: Je ne peux pas dire que j'ai jamais trouvé un besoin légitime d'un NOOP, en dehors de l'assembleur.
Matt Burland
@zmo: Je comprends votre point de vue sur la façon dont vos commentaires se rapportent à l'expression ternaire; tout le monde semble avoir manqué mon argument selon lequel il ne s'agissait que d'un exemple illustratif d'un appel à la fonction "Aucune opération".
kmiklas
1
Bien sûr, il y a des raisons de vouloir / d'avoir besoin d'une fonctionnalité non opérationnelle. Ne faites pas de généralisations générales basées sur vos 12 secondes de réflexion approfondie sur quelque chose. JavaScript est un langage qui rend les fonctions entièrement contrôlables en tant que variables. Supposons que vous ayez besoin de désactiver une fonction sans test explicite? Ce serait parfait pour ça. Si vous avez une fonction qui apparaît fréquemment, comme une instruction de débogage, ce serait bien de pouvoir la désactiver en réaffectant la fonction à no-op plutôt que d'avoir à ajouter du code supplémentaire pour tester une variable à chaque fois que la fonction apparaît .
bearvarine
2
@bearvarine merci pour la haute opinion que vous avez de moi :-D. Vous avez tout à fait raison dans votre commentaire, mais ce n'est pas vraiment pour la conception de code, juste pour la conception de maquettes à l'aide d'un hack. Ce que vous décrivez est aussi appelé patching de singe, et il y a une raison à cela ;-)
zmo
7

Je pense que jQuery noop()est principalement destiné à empêcher le code de planter en fournissant une fonction par défaut lorsque celle demandée n'est pas disponible. Par exemple, en considérant l'exemple de code suivant, $.noopest choisi si fakeFunctionn'est pas défini, ce qui empêche le prochain appel à fnde se bloquer:

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

Ensuite, noop()permet d'économiser de la mémoire en évitant d'écrire la même fonction vide plusieurs fois partout dans votre code. À propos, $.noopest un peu plus court que function(){}(6 octets enregistrés par jeton). Il n'y a donc aucune relation entre votre code et le modèle de fonction vide. Utilisez null, falseou 0si vous le souhaitez, dans votre cas, il n'y aura aucun effet secondaire. De plus, il convient de noter que ce code ...

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

... est complètement inutile puisque vous n'appellerez jamais la fonction, et celle-ci ...

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

... est d'autant plus inutile que vous appelez une fonction vide, qui est exactement la même chose que ...

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

Remplaçons l'expression ternaire par une ifinstruction pour voir à quel point c'est inutile:

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

Vous pouvez simplement écrire:

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

Ou encore plus court:

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

Pour enfin répondre à votre question, je suppose qu'une "opération non conventionnelle" est celle qui n'est jamais écrite.

feuille
la source
1
Cependant, parfois, vous devez fournir une fonction. Par exemple avec les promesses alors (fn, fn) parfois vous voulez fournir la deuxième fonction mais pas la première fonction. donc vous avez besoin de quelque chose pour un espace réservé ...mypromise.then($.noop, myErrorhandler);
John Henckel
3

J'utilise:

 (0); // nop

Pour tester le temps d'exécution de cette exécution comme suit:

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

résultat: marque: 0.000ms

L'utilisation Boolean( 10 > 9)peut se réduire simplement à ( 10 > 9)quels retours true. L'idée d'utiliser un seul opérande auquel je m'attendais (0);serait falserenvoyée, mais elle renvoie simplement l'argument comme on peut le revoir en effectuant ce test sur la console.

> var a = (0);
< undefined
> a
< 0
Des œufs
la source
1
beaucoup de ceux qui tentent cela obtiendrontargument 0 is not a function
Code Whisperer
4
Vous attribuez simplement 0. IMO noopdevrait être une fonction qui évalue avec le undefinedrésultat.
cchamberlain
1
Comment est cette déclaration (0); attribuer un 0?, où est var et signe égal? Il n'y a pas de nom de fonction devant le (0), donc je ne vois pas comment cela pourrait être un argument? si vous essayez typeof ((0)), il revient sous forme de nombre. Lorsque je réponds à la question, je fournissais une déclaration que j'utilise pour imiter un NOP, mais je suis prêt à changer ma réponse pour simplement utiliser; pour représenter une déclaration vide
Eggs
1
Je pense (0); est une solution acceptable à la question d'OP. Je pense que les gens sont confus parce qu'ils ont trouvé cette page en cherchant une fonction qui ne fait rien, plutôt qu'une instruction qui ne fait rien. L'OP n'aide pas en suggérant initialement function(){}comme solution. L'appel (0)()provoqueraTypeError: 0 is not a function
Benjamin
Je faisais référence à var a = (0);. Un no-op ne devrait pas changer la mémoire et votre exemple d'affectation fait exactement cela. Le (0)seul peut être considéré comme un no-op inutile (il y en a un nombre infini dans JavaScript donc il n'y a rien qui rend votre exemple spécial ici).
cchamberlain
2

Il n'y a absolument pas de pénalité problème ou la performance de l' utilisation de Function.prototypeplus () => {}.

Le principal avantage Function.prototypeest d'avoir une fonction singleton plutôt que de redéfinir une nouvelle fonction anonyme à chaque fois. Il est particulièrement important d'utiliser un no-op comme Function.prototypelors de la définition des valeurs par défaut et de la mémorisation car cela vous donne un pointeur d'objet cohérent qui ne change jamais.

La raison pour laquelle je recommande Function.prototypeplutôt que Functionc'est parce qu'ils ne sont pas les mêmes:

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

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

De plus, les repères d'autres réponses sont trompeurs . En fait, Function.prototypefonctionne plus rapidement que () => {}selon la façon dont vous écrivez et exécutez le benchmark:

Vous ne pouvez pas faire confiance aux benchmarks JS << Appeler spécifiquement des benchmarks sur cette question.

Ne stylisez pas votre code à partir de benchmarks; faites tout ce qui est maintenable et laissez l'interprète déterminer comment optimiser à long terme.

Sawtaytoes
la source