Utilisation de la variable _ (trait de soulignement) avec des fonctions fléchées dans ES6 / Typescript

120

Je suis tombé sur cette construction dans un exemple angulaire et je me demande pourquoi cela est choisi:

_ => console.log('Not using any parameters');

Je comprends que la variable _ signifie que je ne me soucie pas / n'est pas utilisé, mais comme c'est la seule variable, y a-t-il une raison de préférer l'utilisation de _ à:

() => console.log('Not using any parameters');

Il ne peut certainement pas s'agir d'un caractère de moins à taper. La syntaxe () transmet mieux l'intention à mon avis et est également plus spécifique au type car sinon, je pense que le premier exemple aurait dû ressembler à ceci:

(_: any) => console.log('Not using any parameters');

Au cas où cela importerait, c'était le contexte dans lequel il a été utilisé:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}
Arrêt
la source
1
Comment pouvez-vous vous soucier du typage ou de la spécificité du type pour un paramètre qui n'est jamais utilisé?
3
Je suis un développeur C ++ de formation, donc je suppose que je suis toujours préoccupé par la spécificité du type :-).
Arrêter
6
Personnellement, le motif _ => réduit le nombre de crochets facilitant la lecture: doStuff (). Then (() => action ()) vs doStuff (). Then (_ => action ()).
Damien Golding

Réponses:

94

La raison pour laquelle ce style peut être utilisé (et peut-être pourquoi il a été utilisé ici) est qu'il _y a un caractère plus court que ().

Les parenthèses facultatives relèvent du même problème de style que les accolades facultatives . C'est une question de goût et de style de code pour la plupart, mais la verbosité est ici favorisée en raison de la cohérence.

Alors que les fonctions fléchées autorisent un seul paramètre sans parenthèses, il est incompatible avec zéro, un seul déstructuré, un seul repos et plusieurs paramètres:

let zeroParamFn = () => { ... };
let oneParamFn = param1 => { ... };
let oneParamDestructuredArrFn = ([param1]) => { ... };
let oneParamDestructuredObjFn = ({ param1 }) => { ... };
let twoParamsFn = (param1, param2) => { ... };
let restParamsFn = (...params) => { ... };

Bien qu'une is declared but never usederreur ait été corrigée dans TypeScript 2.0 pour les paramètres soulignés, elle _peut également déclencher un unused variable/parameteravertissement à partir d'un linter ou d'un IDE. C'est un argument considérable contre cela.

_peut être classiquement utilisé pour les paramètres ignorés (comme l'autre réponse déjà expliqué). Bien que cela puisse être considéré comme acceptable, cette habitude peut entraîner un conflit avec l' _espace de noms Underscore / Lodash, cela semble également déroutant lorsqu'il y a plusieurs paramètres ignorés. Pour cette raison, il est avantageux d'avoir des paramètres soulignés correctement nommés (pris en charge dans TS 2.0), permet également de gagner du temps sur la détermination de la signature de la fonction et sur la raison pour laquelle les paramètres sont marqués comme ignorés (cela va à l'encontre de l'objectif du _paramètre en tant que raccourci):

let fn = (param1, _unusedParam2, param3) => { ... };

Pour les raisons énumérées ci-dessus, je considérerais personnellement le _ => { ... }style de code comme une mauvaise tonalité à éviter.

Fiole d'Estus
la source
1
C'est un caractère plus court mais c'est le même nombre de touches pour la plupart des IDE, car appuyer sur (vient généralement avec un ). p
Personnellement
69

La ()syntaxe transmet mieux l'intention à mon humble avis et est également plus spécifique au type

Pas exactement. ()dit que la fonction n'attend aucun argument, elle ne déclare aucun paramètre. La fonction .lengthest 0.

Si vous utilisez _, il indique explicitement que la fonction recevra un argument, mais que vous ne vous en souciez pas. La fonction .lengthsera 1, ce qui peut être important dans certains cadres.

Donc, du point de vue du type, il peut être plus précis de le faire (surtout lorsque vous ne le tapez pas avec anymais, disons, _: Event). Et comme vous l'avez dit, c'est un caractère de moins à taper, ce qui est également plus facile à atteindre sur certains claviers.

Bergi
la source
6
Ma première pensée a été que _ rend évident uniquement par convention qu'il n'y a pas d'arguments à prendre en compte pour essayer de comprendre la fonction. Utiliser () le rend explicite, pas besoin de scanner le code pour une éventuelle utilisation de _ (ce qui violerait la convention). Mais vous m'avez ouvert les yeux pour considérer également la valeur de documenter qu'il y a une valeur passée à la fonction, qui autrement ne serait pas toujours évidente.
Arrêt
Je viens de réaliser que mon code est plein de _variables de fonction de flèche s inutilisées , je me demande s'il y a une différence de performance par rapport à l'utilisation()
Mojimi
25

Je suppose que _ =>c'est juste utilisé () =>parce que _c'est courant dans d'autres langues où il n'est pas autorisé à simplement omettre des paramètres comme dans JS.

_ est populaire dans Go et il est également utilisé dans Dart pour indiquer qu'un paramètre est ignoré et probablement d'autres que je ne connais pas.

Günter Zöchbauer
la source
4
Python suit également cette convention, je pense.
Jaime RGP du
7
Cet usage de _a probablement été emprunté à des langages fonctionnels tels que ML et Haskell, où il est bien antérieur à l'invention de Python (sans parler de Go, Dart ou TypeScript).
ruakh
1
Ruby le fait aussi ( po-ru.com/diary/rubys-magic-underscore ) et F # aussi (et d'autres langues influencées par la famille ML)
Mariusz Pawelski
Scala aime le soulignement ( includehelp.com/scala/use-of-underscore-in-scala.aspx ). Quelles autres langues ont pris après ce que Scala fait avec les types anonymes avec soulignement.
Sam
Je suppose que Scala l'a également pris dans une autre langue. Il n'y a pratiquement rien dans les langages de programmation qui n'existait pas déjà dans les années 70: D Surtout de nouvelles façons de combiner les choses.
Günter Zöchbauer
11

Il est possible de faire la distinction entre les deux usages, et certains frameworks l'utilisent pour représenter différents types de callbacks. Par exemple, je pense que le cadre express de nœuds utilise cela pour distinguer les types de middleware, par exemple, les gestionnaires d'erreurs utilisent trois arguments, tandis que le routage en utilise deux.

Une telle différenciation peut ressembler à l'exemple ci-dessous:

const f1 = () => { } // A function taking no arguments
const f2 = _ => { }  // A function with one argument that doesn't use it

function h(ff) { 
  if (ff.length === 0) {
    console.log("No argument function - calling directly");
    ff();
  } else if (ff.length === 1) {
    console.log("Single argument function - calling with 1");
    ff(1);
  }
}

h(f1);
h(f2);

Michael Anderson
la source
1
Ceci est basé sur la réponse de Bergi, mais je pensais que l'ajout d'un exemple était un peu plus d'édition que je n'étais heureux de le faire à quelqu'un d'autre.
Michael Anderson
0

Quand j'ai écrit le post, j'avais l'impression que _c'était le seul moyen de créer des fonctions fléchées sans (), ce qui m'a amené à croire que l'utilisation _pouvait avoir des avantages mineurs, mais je me suis trompé. @Halt a confirmé dans les commentaires qu'il se comporte comme les autres variables, ce n'est pas une construction de langage spéciale.


Je veux mentionner une autre chose que j'ai réalisée à propos de ces fonctions de flèche de soulignement en me testant, je n'ai trouvé mentionné nulle part. Vous pouvez utiliser le trait de soulignement dans la fonction en tant que paramètre , bien que ce ne soit probablement pas l'usage prévu car il est censé représenter un paramètre inutilisé. Pour plus de clarté, je ne recommanderais pas vraiment de l'utiliser de cette façon. mais il peut être utile de savoir pour des choses comme codegolf , des défis où vous écrivez le code le plus court (il s'avère que vous pouvez simplement utiliser n'importe quel caractère sans ()). Je pourrais imaginer des cas d'utilisation réels où les bibliothèques l'utilisent et vous devez l'utiliser même si elles n'ont pas l'intention d'utiliser cette fonctionnalité.

Exemple:

// simple number doubling function
f = _=> {
    _ = _ * 2;
    return _;
}

console.log(f(2)); // returns 4
console.log(f(10)); // returns 20

Testé avec la console Chrome, version 76.0.3809.132 (version officielle) (64 bits)

Matsyir
la source
1
Le trait de soulignement '_' est un nom de variable légal et non une construction de langage spéciale, seulement donné une signification spéciale par convention. Les avertissements Linter concernant les paramètres inutilisés peuvent être réduits au silence à l'aide du préfixe de soulignement. Je suppose que _ en soi, c'est juste le moyen le plus court de dire inutilisé.
Arrêt le
@Halt Merci pour la clarification, bon à savoir à coup sûr. En fait, je ne savais pas que vous pouviez faire des fonctions de flèche sans ()avant de publier ce message, je pensais que _c'était le seul moyen de le faire, c'est pourquoi j'ai décidé de le souligner. Dans cet esprit, il s'avère que ce n'est rien de spécial à utiliser, même pour le golf, car vous pouvez simplement utiliser un personnage ordinaire. Mieux vaut simplement pour suivre les conventions, comme vous l'avez dit.
Matsyir le