web-dev-qa-db-fra.com

Quand l'opérateur de virgule est-il utile?

J'ai lu this question à propos de "l'opérateur de virgule" dans les expressions (,) et de la documentation MDN à ce sujet, mais je ne vois pas de scénario où cela serait utile. 

Alors, quand l'opérateur de virgule est-il utile?

63
gdoron

Ce qui suit n’est probablement pas très utile car vous ne l’écrivez pas vous-même, mais un minifier peut réduire le code à l’aide de l’opérateur virgule. Par exemple:

if(x){foo();return bar()}else{return 1}

deviendrait:

return x?(foo(),bar()):1

L'opérateur ? : peut maintenant être utilisé, car l'opérateur de virgule (dans une certaine mesure) permet d'écrire deux instructions en une seule.

Cette est utile dans la mesure où elle permet une compression nette (39 -> 24 octets ici).


J'aimerais souligner le fait que la virgule dans var a, b est non l'opérateur de virgule, car il n'existe pas dans une expression. La virgule a une signification particulière dans varstatement. a, b dans une expression ferait référence aux deux variables et serait évalué à b, ce qui n'est pas le cas pour var a, b.

103
pimvdb

L'opérateur de virgule vous permet de placer plusieurs expressions à un endroit où une expression est attendue. La valeur résultante de plusieurs expressions séparées par une virgule sera la valeur de la dernière expression séparée par une virgule. 

Personnellement, je ne l'utilise pas très souvent car il n'y a pas beaucoup de situations dans lesquelles plus d'une expression est attendue et il n'y a pas de moyen moins déroutant d'écrire le code que d'utiliser l'opérateur de virgule. Une possibilité intéressante est à la fin d'une boucle for lorsque vous souhaitez incrémenter plus d'une variable:

// j is initialized to some other value
// as the for loop executes both i and j are incremented
// because the comma operator allows two statements to be put in place of one
for (var i = 0; i < items.len; i++, j++) {
    // loop code here that operates on items[i] 
    // and sometimes uses j to access a different array
}

Ici, vous voyez que i++, j++ peut être placé à un endroit où une expression est autorisée. Dans ce cas particulier, les expressions multiples sont utilisées pour les effets latéraux; il n’est donc pas important que les expressions composées prennent la valeur du dernier, mais il existe d’autres cas dans lesquels cela pourrait avoir de l’importance.

31
jfriend00

L'opérateur de virgule est souvent utile lors de l'écriture de code fonctionnel en Javascript.

Considérez ce code que j'ai écrit pour un SPA il y a quelque temps et qui ressemblait à ce qui suit

const actions = _.chain(options)
                 .pairs() // 1
                 .filter(selectActions) // 2
                 .map(createActionPromise) // 3
                 .reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
                 .value();

C'était un scénario assez complexe, mais réel. Restez avec moi pendant que j'explique ce qui se passe et, dans le même temps, plaide en faveur de l'opérateur de virgule .


Ceci utilise le chaînage de Underscore pour 

  1. Décomposez toutes les options passées à cette fonction en utilisant pairs Ce qui transformera { a: 1, b: 2} en [['a', 1], ['b', 2]]

  2. Ce tableau de paires de propriétés est filtré en fonction de celles qui sont considérées comme des "actions" dans le système.

  3. Ensuite, le deuxième index du tableau est remplacé par une fonction qui renvoie une promesse représentant cette action (à l'aide de map)

  4. Enfin, l'appel à reduce fusionnera chaque "tableau de propriétés" (['a', 1]) dans un objet final. 

Le résultat final est une version transformée de l'argument options, qui contient uniquement les clés appropriées et dont les valeurs sont consommables par la fonction appelante.


En regardant juste

.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})

Vous pouvez voir que la fonction de réduction commence par un objet d'état vide, state, et que pour chaque paire représentant une clé et une valeur, la fonction renvoie le même objet state après avoir ajouté une propriété à l'objet correspondant à la paire clé/valeur. En raison de la syntaxe de la fonction de flèche de ECMAScript 2015, le corps de la fonction est une expression. Par conséquent, l'opérateur de virgule permet une fonction "iteratee" concise et utile. 

Personnellement, j’ai rencontré de nombreux cas lors de l’écriture de Javascript dans un style plus fonctionnel avec ECMAScript 2015 + Arrow Functions. Cela dit, avant de rencontrer des fonctions fléchées (comme au moment de la rédaction de la question), je n'avais jamais utilisé l'opérateur de virgule de manière délibérée. 

26
Syynth

Une autre utilisation de l'opérateur de virgule consiste à masquer les résultats qui ne vous intéressent pas dans la réplique ou la console, uniquement pour des raisons de commodité. 

Par exemple, si vous évaluez myVariable = aWholeLotOfText dans la répl ou la console, toutes les données que vous venez d'attribuer seront imprimées. Cela peut être des pages et des pages, et si vous préférez ne pas le voir, vous pouvez plutôt évaluer myVariable = aWholeLotOfText, 'done', et repl/console imprimera simplement «done».

Oriel souligne correctement   this custom toString() ou get() les fonctions pourraient même rendre cela utile.

16
Julian de Bhal

L'opérateur de virgule n'est pas spécifique à JavaScript, il est disponible dans d'autres langages comme C et C++ . En tant qu'opérateur binaire, cela est utile lorsque le premier opérande, qui est généralement une expression, a l'effet secondaire souhaité requis par le deuxième opérande. Un exemple de Wikipédia:

i = a += 2, a + b;

Évidemment, vous pouvez écrire deux lignes de codes différentes, mais utiliser une virgule est une autre option, parfois plus lisible. 

11
taskinoor

Je ne suis pas d’accord avec Flanagan et je dirais que la virgule est vraiment utile et permet d’écrire du code plus lisible et plus élégant, surtout quand vous savez ce que vous faites:

Voici le article très détaillé sur l'utilisation de virgule: 

Plusieurs exemples de là-bas pour la preuve de démonstration:

function renderCurve() {
  for(var a = 1, b = 10; a*b; a++, b--) {
    console.log(new Array(a*b).join('*'));
  }
}

Un générateur de fibonacci:

for (
    var i=2, r=[0,1];
    i<15;
    r.Push(r[i-1] + r[i-2]), i++
); 
// 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377

Trouver le premier élément parent, analogue à la fonction jQuery .parent():

function firstAncestor(el, tagName) {
    while(el = el.parentNode, el && (el.tagName != tagName.toUpperCase()));
    return el;
}

//element in http://ecma262-5.com/ELS5_HTML.htm
var a = $('Section_15.1.1.2'); 

firstAncestor(a, 'div'); //<div class="page">
5
shaman.sir

Je n'ai pas trouvé d'utilisation pratique autre que celle-ci, mais voici un scénario dans lequel James Padolsey utilise joliment cette technique pour la détection IE dans une boucle while:

var ie = (function(){

    var undef,
        v = 3,
        div = document.createElement('div'),
        all = div.getElementsByTagName('i');

    while ( // <-- notice no while body here
        div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
        all[0]
    );

    return v > 4 ? v : undef;

}());

Ces deux lignes doivent exécuter:

div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]

Et à l’intérieur de l’opérateur de virgule, les deux sont évalués bien que l’on ait pu les transformer en déclarations séparées.

4
Sarfraz

Il y a quelque chose d '"étrange" qui peut être fait dans JavaScript en appelant une fonction indirectement en utilisant l'opérateur virgule.

Il existe une description longue ici: Appel de fonction indirect en JavaScript

En utilisant cette syntaxe:

(function() {
    "use strict";
  
    var global = (function () { return this || (1,eval)("this"); })();
    console.log('Global === window should be true: ', global === window);
  
    var not_global = (function () { return this })();
    console.log('not_global === window should be false: ', not_global === window);
  
  }());

Vous pouvez avoir accès à la variable globale car eval fonctionne différemment lorsqu’il est appelé directement ou indirectement.

3
Jeremy J Starcher

Je finis par l’utiliser lors de l’analyse facultative des arguments. Je pense que cela le rend plus lisible et plus concis, de sorte que l'analyse des arguments ne domine pas le corps de la fonction.

/**
 * @param {string} [str]
 * @param {object} [obj]
 * @param {Date} [date]
 */
function f(str, obj, date) {
  // handle optional arguments
  if (typeof str !== "string") date = obj, obj = str, str = "default";
  if (obj instanceof Date) date = obj, obj = {};
  if (!(date instanceof Date)) date = new Date();

  // ...
}
1
Rich Remer

Disons que vous avez un tableau:

arr = [];

Lorsque vous Push sur ce tableau, vous êtes rarement intéressé par la valeur de retour de Push, à savoir la nouvelle longueur du tableau, mais plutôt par le tableau lui-même:

arr.Push('foo')  // ['foo'] seems more interesting than 1

En utilisant l'opérateur virgule, nous pouvons pousser sur le tableau, spécifier le tableau comme dernier opérande à virgule, puis utiliser le résultat - le tableau lui-même - pour un appel de méthode tableau suivant, une sorte de chaînage:

(arr.Push('bar'), arr.Push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
0
George Jempty

J'ai trouvé l'opérateur de virgule le plus utile lorsque vous écrivez des aides de ce type.

const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);

Vous pouvez remplacer la virgule par un || ou &&, mais vous devez alors savoir ce que la fonction renvoie.

Plus important encore, le séparateur de virgule communique intention - le code ne s’intéresse pas à ce que l’opérande de gauche évalue, alors que les alternatives peuvent avoir une autre raison d’être là. Cela facilite la compréhension et la refactorisation. Si le type de retour de fonction change, le code ci-dessus ne sera pas affecté.

Naturellement, vous pouvez obtenir la même chose par d'autres moyens, mais pas aussi succinctement. Si || et && ont trouvé une place dans l’utilisation courante, tout comme l’opérateur par virgule.

0