J'ai lu cette question sur «l'opérateur virgule» dans expressions ( ,
) et la documentation MDN à ce sujet, mais je ne peux pas penser à un scénario où il est utile.
Alors, quand l'opérateur virgule est-il utile?
J'ai lu cette question sur «l'opérateur virgule» dans expressions ( ,
) et la documentation MDN à ce sujet, mais je ne peux pas penser à un scénario où il est utile.
Alors, quand l'opérateur virgule est-il utile?
,
opérateur. Cette ligne est également valide dans C#
, mais l' ,
opérateur n'existe pas là-bas.
,
n'est pas toujours l' ,
opérateur (et ce n'est jamais l' ,
opérateur en C #). Ainsi, C # peut manquer d' ,
opérateur tout en l'utilisant librement ,
dans le cadre de la syntaxe.
,
n'est pas largement utilisé (et toutes les occurrences de a ne ,
sont pas l'opérateur virgule) . Mais vous pouvez l'emprunter et un tableau pour effectuer un échange de variables en ligne sans créer de variable temporaire. Étant donné que vous souhaitez échanger les valeurs de a
et b
, vous pouvez le faire a = [b][b = a,0]
. Cela place le courant b
dans le tableau. La seconde []
est la notation d'accès aux propriétés. L'indice est accessible 0
, mais pas avant d' attribuer a
à b
, qui est maintenant en sécurité depuis b
est conservée dans le tableau. le ,
permet de faire les multiples expressions dans le []
.
Réponses:
Ce qui suit n'est probablement pas très utile car vous ne l'écrivez pas vous-même, mais un minificateur 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 être utilisé maintenant, car l'opérateur virgule (dans une certaine mesure) permet d'écrire deux instructions comme une seule instruction.
Ceci est utile dans la mesure où cela permet une compression nette (39 -> 24 octets ici).
Je tiens à souligner le fait que la virgule var a, b
n'est pas l'opérateur virgule car elle n'existe pas dans une expression . La virgule a une signification particulière dans les var
déclarations . a, b
dans une expression ferait référence aux deux variables et évaluerait b
, ce qui n'est pas le cas pour var a, b
.
if (condition) var1 = val1, var2 = val2;
je pense personnellement qu'éviter les crochets lorsque cela est possible rend le code plus lisible.
L'opérateur 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 des virgules.
Personnellement, je ne l'utilise pas très souvent car il n'y a pas beaucoup de situations où plus d'une expression est attendue et il n'y a pas de façon moins déroutante d'écrire le code que d'utiliser l'opérateur virgule. Une possibilité intéressante est à la fin d'une for
boucle lorsque vous voulez que plus d'une variable soit incrémentée:
// 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 qui i++, j++
peut être placé dans un endroit où une expression est autorisée. Dans ce cas particulier, les expressions multiples sont utilisées pour les effets secondaires, donc peu importe que les expressions composées prennent la valeur de la dernière, mais il existe d'autres cas où cela peut réellement avoir de l'importance.
L'opérateur 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 qui avait quelque chose comme 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, ce faisant, plaidez pour l'opérateur virgule.
Démonter toutes les options passées à cette fonction à l' aide pairs
qui va se transformer { a: 1, b: 2}
en[['a', 1], ['b', 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.
Ensuite, le deuxième index du tableau est remplacé par une fonction qui renvoie une promesse représentant cette action (en utilisant map
)
Enfin, l'appel à reduce
fusionnera chaque "tableau de propriétés" ( ['a', 1]
) en un objet final.
Le résultat final est une version transformée de l' options
argument, 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 pour chaque paire représentant une clé et une valeur, la fonction renvoie le même state
objet 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 d'ECMAScript 2015, le corps de la fonction est une expression et, par conséquent, l'opérateur virgule permet une fonction "iteratee" concise et utile .
Personnellement, j'ai rencontré de nombreux cas en écrivant du 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 l'écriture de la question), je n'avais jamais utilisé l'opérateur virgule de manière délibérée.
reduce
.reduce((state, [key, value]) => (state[key] = value, state), {})
. Et je me rends compte que cela va à l'encontre du but de la réponse, mais .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})
éliminerait complètement le besoin de l'opérateur virgule.
Une autre utilisation de l'opérateur virgule est de masquer les résultats qui ne vous intéressent pas dans la réplique ou la console, pour des raisons de commodité.
Par exemple, si vous évaluez myVariable = aWholeLotOfText
dans le repl ou la console, il imprimera toutes les données que vous venez d'attribuer. Cela peut être des pages et des pages, et si vous préférez ne pas le voir, vous pouvez à la place évaluer myVariable = aWholeLotOfText, 'done'
, et le repl / console affichera simplement «done».
Oriel souligne correctement † que des fonctions toString()
ou des get()
fonctions personnalisées peuvent même rendre cela utile.
L'opérateur 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 un effet secondaire souhaité requis par le second opérande. Un exemple de wikipedia:
i = a += 2, a + b;
Évidemment, vous pouvez écrire deux lignes de codes différentes, mais l'utilisation de la virgule est une autre option et parfois plus lisible.
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 élégant, surtout quand vous savez ce que vous faites:
Voici l' article très détaillé sur l'utilisation de la 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
Trouvez le premier élément parent, analogue de la .parent()
fonction jQuery :
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">
while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))
serait très bien dans ce contexte.
Je n'ai pas trouvé d'utilisation pratique autre que cela, mais voici un scénario dans lequel James Padolsey utilise bien 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 s'exécuter:
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
Et à l'intérieur de l'opérateur virgule, les deux sont évalués bien que l'on aurait pu leur faire des déclarations séparées d'une manière ou d'une autre.
do
- while
boucle.
Il y a quelque chose d '«étrange» qui peut être fait en JavaScript en appelant indirectement une fonction en utilisant l'opérateur virgule.
Il y a une longue description ici: Appel de fonction indirecte 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 accéder à la variable globale car elle eval
fonctionne différemment lorsqu'elle est appelée directement ou indirectement.
J'ai trouvé l'opérateur virgule le plus utile lors de l'écriture d'aides comme celle-ci.
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 par virgule communique l' intention - le code ne se soucie pas de ce que l'opérande de gauche évalue, alors que les alternatives peuvent avoir une autre raison d'être là. Cela facilite à son tour la compréhension et la refactorisation. Si le type de retour de fonction change un jour, le code ci-dessus ne sera pas affecté.
Naturellement, vous pouvez réaliser la même chose par d'autres moyens, mais pas aussi succinctement. Si || et && a trouvé une place dans l'usage courant, de même que l'opérateur virgule.
tap
( ramdajs.com/docs/#tap ). Essentiellement, vous exécutez un effet secondaire, puis vous renvoyez la valeur initiale; très utile en programmation fonctionnelle :)
Un cas typique dans lequel je finis par l'utiliser est lors de l'analyse d'arguments facultatifs. Je pense que cela le rend à la fois plus lisible et plus concis afin 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();
// ...
}
Disons que vous avez un tableau:
arr = [];
Lorsque vous êtes push
sur ce tableau, vous êtes rarement intéressé par push
la valeur de retour de 's, à savoir la nouvelle longueur du tableau, mais plutôt 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 à la virgule, puis utiliser le résultat - le tableau lui-même - pour un appel de méthode de tableau suivant, une sorte de chaînage:
(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
Un autre domaine dans lequel l'opérateur virgule peut être utilisé est l' obscurcissement du code .
Disons qu'un développeur écrit du code comme celui-ci:
var foo = 'bar';
Maintenant, elle décide de masquer le code. L'outil utilisé peut changer le code comme ceci:
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'
var i, j, k;
vsvar i; var j, var k
?