Cette procédure est similaire aux autres "Conseils pour jouer au golf dans <...>", mais elle cible spécifiquement les nouvelles fonctionnalités JavaScript introduites dans ECMAScript 6 et versions ultérieures.
JavaScript est intrinsèquement un langage très prolixe function(){}
,.forEach()
, chaîne de conversion à un tableau, un objet semblable à un tableau de tableau, etc, etc sont bloats super et pas sain pour le golf.
L'ES6 +, en revanche, présente des fonctionnalités extrêmement pratiques et un encombrement réduit. x=>y
,[...x]
etc. ne sont que quelques exemples.
S'il vous plaît postez quelques astuces qui peuvent aider à réduire ces quelques octets supplémentaires de votre code.
REMARQUE: les astuces pour ES5 sont déjà disponibles dans Astuces pour le golf en JavaScript. . les réponses à ce fil doivent se concentrer sur des astuces uniquement disponibles dans ES6 et d'autres versions futures d'ES.
Toutefois, ce fil est également destiné aux utilisateurs qui utilisent actuellement les fonctionnalités ES5 pour jouer au golf. Les réponses peuvent également contenir des conseils pour les aider à comprendre et à mapper les fonctionnalités de ES6 à leur style de codage ES5.
la source
Trucs appris ici depuis mon arrivée
Mon langage de programmation principal est JS et principalement ES6. Depuis que j'ai rejoint ce site il y a une semaine, j'ai appris beaucoup de trucs utiles de la part de mes collègues. Je combine certains de ceux ici. Tous les crédits à la communauté.
Fonctions de flèche et boucles
Nous savons tous que les fonctions de flèche permettent d'économiser beaucoup de byts
Mais vous devez garder à l'esprit quelques petites choses
,
ie(a=b,a.map(d))
- Ici, la valeur renvoyée est la dernière expression.a.map(d)
do something
partie est plus d'une déclaration, alors vous devez ajouter le entourage{}
parenthèses.{}
crochets, vous devez ajouter une instruction de retour explicite.Ce qui précède s’applique bien souvent lorsque des boucles sont impliquées. Donc, quelque chose comme:
Ici, je gaspille au moins 9 caractères à cause du retour. Cela peut être optimisé.
.map
ou.every
ou à la.some
place. Notez que si vous souhaitez modifier le même tableau sur lequel vous mappez, cela échouera.Donc ce qui précède devient:
caractères supprimés:
{}return
caractères ajoutés:
(){}>|
Notez comment j'appelle la méthode de fermeture, qui remplit correctement la variable
n
, puis, puisque la méthode de fermeture ne renvoie rien (c.-à-dundefined
., Retourne), j'utilise bitwise ou elle et renvoie le tableaun
dans une seule instruction de la fonction de flèche extérieure.u
Virgules et points-virgules
Evite-les,
Si vous déclarez des variables dans une boucle, ou comme mentionné dans la section précédente, en utilisant
,
des instructions séparées pour avoir des fonctions de flèche d'instructions simples, vous pouvez utiliser quelques astuces assez astucieuses pour les éviter,
ou;
pour supprimer les derniers octets.Considérons ce code:
Ici, j'appelle beaucoup de méthodes pour initialiser beaucoup de variables. Chaque initialisation utilise un
,
ou;
. Cela peut être réécrit comme:Notez comment j'utilise le fait que la méthode ne gêne pas la variable qui lui est transmise et utilisez ce fait pour supprimer 3 octets.
Misc
.search
au lieu de.indexOf
Les deux donnent le même résultat mais
search
sont plus courts. Bien que la recherche attende une expression régulière, utilisez-la à bon escient.`Template Strings`
Celles-ci sont très pratiques lorsque vous devez concaténer une ou plusieurs parties de cordes en fonction de certaines conditions.
Prenons l'exemple suivant pour sortir une quine dans JS
contre.
Dans une chaîne de modèle, qui est une chaîne à l'intérieur de deux guillemets arrières (`), tout élément à l'intérieur d'un élément
${ }
est traité comme un code et évalué pour insérer la réponse résultante dans la chaîne.Je posterai quelques astuces plus tard. Bon golf!
la source
regexp
, pas une chaîne. Essayez'abc'.search('.')
.map
, la récursivité est une autre technique qui peut parfois vous aider à transformer unefor
boucle en expression.Utiliser des raccourcis de propriété
Les raccourcis de propriété vous permettent de définir des variables sur les valeurs d'un tableau:
Cela peut aussi être utilisé comme:
Vous pouvez même l'utiliser pour inverser des variables:
Vous pouvez également l'utiliser pour raccourcir les
slice()
fonctions.Conversions de base
ES6 fournit un moyen beaucoup plus court de convertir les formulaires Base-2 (binaire) et Base-8 (octal) en décimal:
+
peut être utilisé pour convertir une chaîne binaire, octale ou hexadécimale en un nombre décimal. Vous pouvez utiliser0b
,0o
et0x
, respectivement pour binaire, octal et hex .:Si vous utilisez ceci> 7 fois, il sera alors plus court à utiliser
parseInt
et à le renommer:Vous
p
pouvez maintenant utiliser cette option pourparseInt
économiser de nombreux octets sur le long terme.la source
'0x'+v-0
est même plus court, mais peut ne pas fonctionner aussi bien dans certains scénarios.0767
(ES5) est plus court que la0o767
notation (ES6).0767
est une extension non standard, elle est explicitement interdite en mode strict.0
Les littéraux octaux pré-préfixés ne vont nulle part et sont aussi valables que ecmascript0o
.Utilisation de modèles de chaîne avec des fonctions
Lorsque vous avez une fonction avec une chaîne comme arguments. Vous pouvez omettre le
()
si vous n'avez aucune expression:la source
fun`string`
est le même quefun(["string"])
, pasfun("string")
. Cela convient pour les fonctions qui transtypent en chaîne, par exemplealert
, mais pour d’autres, cela pourrait poser des problèmes. Pour plus d'informations, voir l'article de MDNfun`foo${1}bar${2}baz
équivaut à appelerfun(["foo","bar","baz"],1,2)
Compréhensions des tableaux (Firefox 30-57)
Remarque: la compréhension des tableaux n’a jamais été normalisée et est devenue obsolète avec Firefox 58. Utilisez-le à vos risques et périls.
A l'origine, la spécification ECMAScript 7 contenait un ensemble de nouvelles fonctionnalités basées sur des tableaux. Bien que la plupart d’entre elles n’aient pas été intégrées à la version finalisée, Firefox supportait (peut-être) la plus grande de ces fonctionnalités: une nouvelle syntaxe élégante qui peut remplacer
.filter
et.map
avec lafor(a of b)
syntaxe. Voici un exemple:Comme vous pouvez le constater, les deux lignes ne sont pas si différentes que la seconde ne contenant pas les mots-clés volumineux et les fonctions de flèche. Mais cela ne représente que la commande
.filter().map()
; que se passe-t-il si vous en avez à la.map().filter()
place? Cela dépend vraiment de la situation:Ou si vous voulez soit
.map
ou.filter
? Eh bien, il s’avère généralement moins OK:Donc , mon conseil est d'utiliser du tableau où compréhensions vous habituellement utiliser
.map
et.filter
, mais pas seulement l' un ou l'autre.String Compréhensions
Une bonne chose à propos des interprétations d'ES7 est que, contrairement aux fonctions spécifiques aux tableaux telles que
.map
et.filter
, elles peuvent être utilisées sur n'importe quel objet itératif, pas seulement sur des tableaux. Ceci est particulièrement utile lorsqu'il s'agit de chaînes. Par exemple, si vous souhaitez exécuter chaque caractèrec
d'une chaîne viac.charCodeAt()
:C'est deux octets sauvés sur une assez petite échelle. Et si vous voulez filtrer certains caractères d'une chaîne? Par exemple, celui-ci ne conserve que des lettres majuscules:
Hmm, ce n'est pas plus court. Mais si nous combinons les deux:
Wow, 10 octets sauvés!
Un autre avantage de la compréhension des chaînes est que les chaînes codées en dur enregistrent un octet supplémentaire, car vous pouvez omettre l'espace après
of
:Indexage
Les compréhensions de tableau rendent un peu plus difficile d'obtenir l'index actuel dans la chaîne / tableau, mais cela peut être fait:
La principale chose à faire est de s’assurer que l’index est incrémenté à chaque fois, pas seulement lorsqu’une condition est remplie.
Compréhensions du générateur
Les compréhensions de générateur ont fondamentalement la même syntaxe que les compréhensions de tableau; remplacez simplement les crochets par des parenthèses:
Cela crée un générateur qui fonctionne à peu près de la même manière qu'un tableau, mais c'est une histoire pour une autre réponse.
Sommaire
Fondamentalement, bien que les compréhensions soient généralement plus courtes que tout
.map().filter()
, tout dépend des spécificités de la situation. Il est préférable d'essayer les deux manières et voir ce qui fonctionne le mieux.PS N'hésitez pas à suggérer un autre conseil relatif à la compréhension ou un moyen d'améliorer cette réponse!
la source
(x,y)=>[...Array(y-x)].map(a=>x++)
x=>[...Array(x).keys()]
n=>[for(x of Array(n).keys())if(/1/.test(x))x]
(sauvegarde de 7 octets)Les expressions de fonction dans ES6 utilisent la notation en flèche, ce qui permet d'économiser beaucoup d'octets par rapport à la version ES5:
Si votre fonction n'a qu'un seul paramètre, vous pouvez omettre les parenthèses pour enregistrer deux octets:
Si votre fonction n'a aucun paramètre, déclarez-la comme si elle en avait un pour enregistrer un octet:
Attention: les fonctions des flèches ne sont pas exactement les mêmes que
function () {}
. Les règles pourthis
sont différentes (et meilleure IMO). Voir docsla source
this
etc.f=(...x)=>x
aurait celaf(1,2,3) => [1,2,3]
.(x,y)=>...
vous pouvez enregistrer un octet avec curry en le remplaçant parx=>y=>...
Utilisation
eval
des fonctions de flèche avec plusieurs instructions et unreturn
Un des trucs les plus ridicules que je suis tombé sur ...
Imaginez une simple fonction de flèche nécessitant plusieurs déclarations et a
return
.Une fonction simple acceptant un seul paramètre
a
, qui itère sur tous les entiers de[0, a)
et les pointe à la fin de la chaîne de sortieo
, qui est renvoyée. Par exemple, appeler ceci avec4
comme paramètre produirait0123
.Notez que cette fonction de flèche devait être entourée d’accolades
{}
et avoir unreturn o
à la fin.Cette première tentative pèse 39 octets .
Pas mal, mais en utilisant
eval
, nous pouvons améliorer cela.Cette fonction supprime les accolades et l’instruction return en encapsulant le code dans un
eval
et en faisant simplement la dernière instruction de l’eval
évaluationo
. Cela provoque leeval
retouro
, ce qui à son tour provoque le retour de la fonctiono
, puisqu'il s'agit maintenant d'une seule instruction.Cette tentative améliorée pèse 38 octets , économisant un octet de l'original.
Mais attendez, il y a plus! Les instructions Eval renvoient quelle que soit leur dernière instruction évaluée. Dans ce cas,
o+=i
évalue ào
, nous n'avons donc pas besoin du;o
! (Merci, edc65!)Cette dernière tentative ne pèse que 36 octets - une économie de 3 octets par rapport à l'original!
Cette technique peut être étendue à tous les cas généraux où une fonction de flèche doit renvoyer une valeur et avoir plusieurs instructions (qui ne pourraient pas être combinées par d'autres moyens).
devient
enregistrer un octet.
Si
statement2
évalue àv
, cela peut êtreéconomiser un total de 3 octets.
la source
;o
essayer:a=>eval('for(o="",i=0;i<a;i++)o+=i')
Préférez les nouvelles lignes de la chaîne de modèle à "\ n"
Cela commencera à porter ses fruits même avec un seul caractère de nouvelle ligne dans votre code. Un cas d'utilisation pourrait être:
(16 octets)
(15 octets)
Mise à jour: Vous pouvez même laisser les accolades à cause des chaînes de modèles étiquetées (merci, edc65!):
(13 octets)
la source
Remplissage des tableaux - Valeurs statiques et plages dynamiques
Au départ, je les ai laissés sous la forme de commentaires, mais comme cet article était principalement axé sur la compréhension, je me suis dit que ce serait bien de lui donner sa place.
ES6 nous a donné la possibilité de remplir des tableaux avec des valeurs statiques sans utiliser de boucles:
Les deux renvoient un tableau de longueur x, rempli avec la valeur 0.
Si vous souhaitez remplir des tableaux avec des valeurs dynamiques (comme une plage de 0 ... x), le résultat est un peu plus long (bien qu'il soit encore plus court que l'ancien):
Tous deux renvoient un tableau de longueur x, commençant par la valeur 0 et se terminant par x-1.
La raison pour laquelle vous avez besoin
.fill()
de là est parce que simplement initialiser un tableau ne vous laissera pas le mapper. C'est-à-dire que fairex=>Array(x).map((a,i)=>i)
retournera un tableau vide. Vous pouvez également contourner le besoin de remplissage (et le rendre ainsi encore plus court) en utilisant l'opérateur de propagation comme suit:En utilisant l'opérateur et la
.keys()
fonction spread , vous pouvez maintenant créer une courte plage 0 ... x:Si vous voulez une plage personnalisée de x ... y, ou une plage spécialisée (comme des nombres pairs), vous pouvez vous débarrasser de
.keys()
et simplement utiliser.map()
, ou utiliser.filter()
, avec l'opérateur de propagation:la source
x=>Array(x).fill(i=0).map(a=>i++)
De plus, je ne suis pas sûr que le 0 dans.fill(0)
soit nécessaire. Avez-vous essayé sans?a=>a%2-1
fonctionne bien, comme le faita=>a%2<1
.[...Array(x)]
fonctionne aussi bienArray(x).fill()
et est plus courte de 2 octets.x=>[...Array(x)].map((a,i)=>i)
1/4
exemple serait plus court[0,0,0,0]
et 2) les fonctions stringifiées sont spécifiques à l'implémentation. Par conséquent, elles ne renverront pas une longueur fiable (Map
32 octets dans Chrome, mais 36 octets dans Firefox).Renvoi de valeurs dans les fonctions de flèche
Il est de notoriété publique que si une seule instruction suit la déclaration de la fonction de flèche, elle renvoie le résultat de cette instruction:
-7 octets
Donc, lorsque cela est possible, combinez plusieurs déclarations en une seule. Cela se fait plus facilement en entourant les instructions de parenthèses et en les séparant par des virgules:
-8 octets
Mais s'il n'y a que deux déclarations, il est généralement possible (et plus court) de les combiner avec
&&
ou||
:-9 octets
Enfin, si vous utilisez map (ou similaire) et que vous avez besoin de renvoyer un nombre et que vous puissiez vous assurer que la carte ne renverra jamais un tableau de 1 longueur avec un nombre, vous pouvez renvoyer le nombre avec
|
:la source
Hacks aléatoires de chaînes de modèles
Cette fonction génère deux chaînes (c.-à-d. Se transforme
"abc","de"
en"adbec"
):Notez que cela ne fonctionne que quand
x
est plus long quey
. Comment ça marche, demandez-vous?String.raw
est conçu pour être une balise de modèle, comme suit:Ceci appelle essentiellement
String.raw(["x: ", "\ny: ", "\nx + y: ", ""], x, y, x + y)
, bien que ce ne soit pas si simple. Le tableau de modèles a également uneraw
propriété spéciale , qui est essentiellement une copie du tableau, mais avec les chaînes brutes.String.raw(x, ...args)
revient essentiellementx.raw[0] + args[0] + x.raw[1] + args[1] + x.raw[2] + ...
et ainsi de suite jusqu'à épuisementx
des éléments.Alors maintenant que nous savons comment ça
String.raw
marche, nous pouvons l’utiliser à notre avantage:Bien sûr, pour ce dernier,
f=(x,y)=>x.split``.join(y)
c'est beaucoup plus court, mais vous voyez l'idée.Voici quelques fonctions qui fonctionnent aussi si
x
ety
ont la même longueur:Vous pouvez en apprendre plus
String.raw
sur MDN .la source
Comment jouer au golf avec récursion
La récursion, bien que n'étant pas l'option la plus rapide, est très souvent la plus courte. En règle générale, la récursivité est la plus courte si la solution peut être simplifiée, mais surtout si l’entrée est un nombre ou une chaîne. Par exemple, si
f("abcd")
peut être calculé à partir de"a"
etf("bcd")
, il est généralement préférable d'utiliser la récursivité.Prenons, par exemple, factorielle:
Dans cet exemple, la récursivité est évidemment beaucoup plus courte que toute autre option.
Que diriez-vous de la somme des charcodes:
Celui-ci est plus compliqué, mais nous pouvons voir que lorsqu'il est correctement implémenté, la récursivité économise 4 octets
.map
.Voyons maintenant les différents types de récursivité:
Pré-récursion
C'est généralement le type de récursivité le plus court. L'entrée est divisée en deux parties
a
etb
, et la fonction calcule quelque chose aveca
etf(b)
. Revenons à notre exemple factoriel:Dans ce cas,
a
est n ,b
est n-1 , et la valeur retournée esta*f(b)
.Remarque importante: Toutes les fonctions récursives doivent avoir un moyen d'arrêter de récursir lorsque l'entrée est suffisamment petite. Dans la fonction factorielle, ceci est contrôlé avec le
n? :1
, c'est-à-dire que si l'entrée est 0 , retourne 1 sans appeler àf
nouveau.Post-récurrence
La post-récurrence est similaire à la pré-récursion, mais légèrement différente. L'entrée est divisée en deux parties
a
etb
, et la fonction calcule quelque chose aveca
, puis appellef(b,a)
. Le second argument a généralement une valeur par défaut (ief(a,b=1)
).La pré-récursivité est bonne lorsque vous devez faire quelque chose de spécial avec le résultat final. Par exemple, si vous voulez la factorielle d’un nombre plus 1:
Cependant, même dans ce cas, la post-utilisation n’est pas toujours plus courte que l’utilisation de la pré-récursion dans une autre fonction:
Alors, quand est-ce plus court? Vous remarquerez peut-être que la post-récursion dans cet exemple nécessite des parenthèses autour des arguments de la fonction, contrairement à la pré-récursion. En règle générale, si les deux solutions nécessitent des parenthèses autour des arguments, la post-récurrence est environ 2 octets plus courte:
(programmes ici tirés de cette réponse )
Comment trouver la solution la plus courte
Habituellement, la seule façon de trouver la méthode la plus courte est de toutes les essayer. Ceci comprend:
.map
(pour les chaînes,[...s].map
ous.replace
; pour les nombres, vous pouvez créer une plage )Et ce ne sont que les solutions les plus courantes; la meilleure solution pourrait être une combinaison de ceux-ci, ou même quelque chose de complètement différent . La meilleure façon de trouver la solution la plus courte est de tout essayer .
la source
Des façons plus courtes de faire
.replace
Si vous souhaitez remplacer toutes les occurrences d'une sous-chaîne exacte par une autre dans une chaîne, la solution évidente serait la suivante:
Cependant, vous pouvez faire un octet plus court:
Notez que cela n’est plus plus court si vous souhaitez utiliser des fonctionnalités regex autres que le
g
drapeau. Cependant, si vous remplacez toutes les occurrences d'une variable, celle-ci est généralement beaucoup plus courte:Parfois, vous aurez envie de mapper chaque caractère d'une chaîne en remplaçant chaque caractère par quelque chose d'autre. Je me retrouve souvent à faire ça:
Cependant,
.replace
est presque toujours plus courte:Maintenant, si vous voulez mapper chaque caractère d'une chaîne sans vous soucier de la chaîne résultante, il
.map
est généralement préférable de se débarrasser de.join``
:la source
/\w/g
) sont intéressés, utiliser remplacer sera beaucoup mieux comme dans cette démo .Écrire des littéraux RegEx avec
eval
Le constructeur de regex peut être très volumineux à cause de son nom long. Au lieu de cela, écrivez un littéral avec eval et backticks:
Si la variable
i
est égale àfoo
, cela va générer:Ceci est égal à:
Vous pouvez également utiliser
String.raw
pour éviter d'avoir à échapper à plusieurs reprises des barres obliques inverses\
Cela produira:
Qui est égal à:
Garder en tete!
String.raw
prend beaucoup d'octets et à moins que vous ayez au moins neuf barres obliques inverses, ceString.raw
sera plus long.la source
new
de là dedans, donc utiliser le constructeur est en fait plus court pour le deuxième exemple.forEach
contrefor
bouclesToujours préférer
.map
à n'importe quelle boucle. Économies faciles et instantanées.la source
Utilisation de compteurs non initialisés en récursivité
Remarque : Strictement parlant, ceci n'est pas spécifique à ES6. Cependant, il est plus logique d'utiliser et d'abuser de la récursivité dans ES6 en raison de la nature concise des fonctions fléchées.
Il est assez courant de rencontrer une fonction récursive qui utilise un compteur
k
initialement défini à zéro et incrémenté à chaque itération:Dans certaines circonstances, il est possible d'omettre l'initialisation d'un tel compteur et de le remplacer
k+1
par-~k
:Cette astuce enregistre généralement 2 octets .
Pourquoi et quand ça marche?
La formule qui le rend possible est
~undefined === -1
. Donc, à la première itération,-~k
sera évalué à1
. Sur les itérations suivantes,-~k
est essentiellement équivalent à-(-k-1)
qui égalek+1
, au moins pour les entiers compris dans l'intervalle [0… 2 31 -1].Vous devez cependant vous assurer que
k = undefined
la première itération ne perturbera pas le comportement de la fonction. Il faut surtout garder à l’esprit que la plupart des opérations arithmétiques impliquantundefined
aboutiront àNaN
.Exemple 1
Étant donné un entier positif
n
, cette fonction recherche le plus petit entierk
qui ne se divise pasn
:Il peut être réduit à:
Cela fonctionne parce que
n % undefined
estNaN
, ce qui est de la fausseté. C'est le résultat attendu à la première itération.[Lien vers la réponse originale]
Exemple n ° 2
Étant donné un entier positif
n
, cette fonction recherche un entierp
tel que(3**p) - 1 == n
:Il peut être réduit à:
Cela fonctionne car il
p
n'est pas utilisé du tout à la première itération (n<k
étant faux).[Lien vers la réponse originale]
la source
Fonctions ES6
Math
Math.cbrt(x)
enregistre des caractères queMath.pow(x,1/3)
.3 caractères sauvegardés
Math.hypot(...args)
est utile lorsque vous avez besoin de la racine carrée de la somme des carrés des arguments. Il est beaucoup plus difficile de créer du code ES5 que d’utiliser un logiciel intégré.La fonction
Math.trunc(x)
ne serait pas utile, carx|0
est plus courte. (Merci Mwr247!)Il existe de nombreuses propriétés qui nécessitent beaucoup de code dans ES5, mais plus faciles dans ES6:
Math.acosh
,asinh
,atanh
,cosh
,sinh
,tanh
. Calcule l'équivalent hyperbolique des fonctions trigonométriques.Math.clz32
. Cela pourrait être possible dans ES5, mais c'est plus facile maintenant. Compte les zéros en tête dans la représentation 32 bits d'un nombre.Il y a beaucoup plus, donc je vais juste énumérer quelques - unes:
Math.sign
,Math.fround
,Math.imul
,Math.log10
,Math.log2
,Math.log1p
.la source
Math.trunc(x)
est quatre fois plus long quex|0
.Math.hypot(a,b) => Math.sqrt(a*a+b*b)
(3 octets de plus; devient encore plus long avec plus d'arguments),Math.sign(a) => (a>0)-(a<0)
(1 octet de moins, mais il faut parfois entourer les parenthèses; peut ne pas fonctionnerNaN
)Optimisation de petites plages constantes pour
map()
Le contexte
map()
for
peut être remplacé par:
ou plus communément:
Array(N)
NB : La longueur du code de rappel
F(i)
n'est pas comptée.Optimisations sans compteur
NB : La longueur du code de rappel
F()
n'est pas comptée.la source
2**26
être2**29
?.keys()
, vous n'avez pas besoin d'un lambda:[...Array(10).keys()].map(do_something_with)
Missions de restructuration
ES6 introduit une nouvelle syntaxe pour les assignations de déstructuration, c'est-à-dire couper une valeur en morceaux et affecter chaque morceau à une variable différente. Voici quelques exemples:
Cordes et tableaux
Objets
Ces affectations peuvent également être utilisées dans les paramètres de fonction:
la source
Encore un autre moyen d'éviter
return
Vous savez que vous devriez utiliser eval pour les fonctions de flèche avec plusieurs déclarations et un retour . Dans certains cas inhabituels, vous pouvez économiser davantage en utilisant une sous-fonction interne.
Je dis inhabituel parce que
Le résultat renvoyé ne doit pas être la dernière expression évaluée dans la boucle.
Il doit y avoir (au moins) 2 initialisations différentes avant la boucle
Dans ce cas, vous pouvez utiliser une sous-fonction interne sans retour, avec l'une des valeurs initiales passée en paramètre.
Exemple Trouver l'inverse de la fonction sum of exp pour des valeurs comprises entre a et b.
Le long chemin - 55 octets
Avec eval - 54 octets
Avec une fonction interne - 53 octets
Notez que sans l'exigence d'une limite inférieure
a
, je peux fusionner les initialisations de i et r et la version eval est plus courte.la source
a
(i,b)=>{for(r=0;i<=b;i++)r+=Math.exp(i);return 1/r}
return a/r
serait un meilleur exemple(a,b)=>1/eval("for(r=0,i=a;i<=b;i++)r+=Math.exp(i)")
et dans ce cas(i,b)=>1/eval("for(r=0;i<=b;)r+=Math.exp(i++)")
Utilisation de la syntaxe de currying pour les fonctions dyadiques et récursives
Fonctions dyadiques
Lorsqu'une fonction prend exactement deux arguments sans valeur par défaut, la syntaxe de curry enregistre un octet.
Avant
Appelé avec
f(a,b)
Après
Appelé avec
f(a)(b)
Note : Ce post dans Meta confirme la validité de cette syntaxe.
Fonctions récursives
L'utilisation de la syntaxe de currying peut également permettre d'économiser quelques octets lorsqu'une fonction récursive prend plusieurs arguments, mais ne nécessite que de mettre à jour certains d'entre eux entre chaque itération.
Exemple
La fonction suivante calcule la somme de tous les entiers compris dans la plage
[a,b]
:Comme
a
reste inchangé pendant tout le processus, nous pouvons économiser 3 octets en utilisant:Remarque : comme Neil l'a remarqué dans les commentaires, le fait qu'un argument ne soit pas explicitement passé à la fonction récursive ne signifie pas qu'il devrait être considéré comme immuable. Si nécessaire, nous pourrions modifier
a
le code de fonction aveca++
,a--
ou une syntaxe similaire.la source
a=>F=b=>a>b?0:a+++F(b)
, en modifianta
pour chaque appel récursif. Dans ce cas, cela n’aide en rien, mais cela pourrait économiser des octets dans les cas avec plus d’arguments.Fonction de test de primalité
La fonction suivante sur 28 octets est renvoyée
true
pour les nombres premiers etfalse
pour les non-premiers:Cela peut facilement être modifié pour calculer d'autres choses. Par exemple, cette fonction de 39 octets compte le nombre de nombres premiers inférieurs ou égaux à un nombre:
Si vous avez déjà une variable
n
à vérifier pour la primalité, la fonction de primalité peut être simplifiée un peu:Comment ça fonctionne
Remarque: cela échouera avec une erreur "trop de récursivité" s'il est appelé avec une entrée suffisamment grande, telle que 12345. Vous pouvez contourner ce problème avec une boucle:
la source
x==1
peut probablement êtrex<2
pour des économies.1
ou0
(parce quex
serait0
ou-1
, respectivement)!~-x
pour -0 octets.Array#concat()
et l'opérateur de propagationCela dépend en grande partie de la situation.
Combinaison de plusieurs tableaux.
Préférez la fonction concat sauf clonage.
0 octet enregistré
3 octets gaspillés
3 octets enregistrés
6 octets enregistrés
Préférez utiliser un tableau déjà existant pour
Array#concat()
.Facile 4 octets enregistrés
la source
Retour du résultat intermédiaire
Vous savez qu'en utilisant l'opérateur virgule, vous pouvez exécuter une séquence d'expressions renvoyant la dernière valeur. Mais en abusant de la syntaxe de tableau littéral, vous pouvez renvoyer n'importe quelle valeur intermédiaire. C'est utile dans .map () par exemple.
la source
.join('')
peut être.join``
Définir les paramètres par défaut de la fonction
Celui-ci est vraiment utile ...
Cependant, assurez-vous de comprendre que quelque chose comme
_=>_||'asdf'
est plus court lorsque vous ne passez qu'un argument (utile) à la fonction.la source
_=>_||'asdf'
"asdf"
pour une entrée de""
(chaîne vide).undefined
, même si vous transmettez explicitement cette valeur. Par exemple,[...Array(n)].map((a,b,c)=>b)
passe toujoursundefined
poura
, et vous pouvez donc lui fournir une valeur par défaut (mais pas en termes deb
).Utilisez
eval
au lieu d'accolades pour les fonctions de flècheLes fonctions fléchées sont géniales. Ils prennent la forme
x=>y
, oùx
est un argument ety
est la valeur de retour. Cependant, si vous devez utiliser une structure de contrôle, telle quewhile
, vous devez mettre des accolades, par exemple=>{while(){};return}
. Cependant, nous pouvons contourner cela; Heureusement, laeval
fonction prend une chaîne, l'évalue en tant que code JS et renvoie la dernière expression évaluée . Par exemple, comparez ces deux:Nous pouvons utiliser une extension de ce concept pour raccourcir davantage notre code: aux yeux de
eval
, les structures de contrôle renvoient également leur dernière expression évaluée. Par exemple:la source
Opérations logiques de golf dans ES6
"GLOE (S6)"
Logique générale
Supposons que vous avez construit des déclarations
s
ett
. Voyez si vous pouvez utiliser l'un des remplacements suivants:(Celles-ci peuvent ne pas fonctionner si l’ordre est mauvais; c’est
+
-à- dire et*
ont une priorité inférieure à celle de||
et&&
faire.)En outre, voici quelques expressions logiques utiles:
s
out
est vrai / XOR:s^t
s
ett
ont la même valeur de vérité:!s^t
ous==t
Logique de tableau
Tous les membres de
a
satisfaire la conditionp
:Au moins un membre de
a
satisfait à la conditionp
:Aucun membre de
a
condition satisfaitep
:!a.some(p)
.L'élément
e
existe dans le tableaua
:L'élément
e
n'existe pas dans le tableaua
:la source
&&
et||
commex?y:x
etx?x:y
, respectivement. Mais je peux voir en quoi cela serait utile dans des programmes plus logiques. Le seul problème+
serait que, par exemple3
, ils-3
sont tous deux véridiques, mais3+-3
ne l’est pas.-
pourrait aussi fonctionner, sis != t
.a.filter(t=>t==e).length==a.length
est incorrect. Il devrait être!a.filter(t=>t==e).length
Raccourcir les appels de fonction répétés
Si vous avez répété des appels à une fonction portant un nom long, telle que la manipulation de canevas:
La manière traditionnelle de le raccourcir serait d’aliaser le nom de la fonction:
Si vous avez suffisamment d'appels, une meilleure solution consiste à créer une fonction qui effectue le travail à votre place:
Si la plupart des appels de fonction sont chaînés, vous pouvez faire en sorte que la fonction se retourne elle-même, ce qui vous permet de couper deux octets de chaque appel successif:
Exemple d'utilisation: 1 , 2
la source
(l=::c.lineTo)(0,100)(100,100)(100,0)(0,0);c.stroke()
c.lineTo
il ne revient pas naturellement lui-même)Opérateur de liaison
::
L'opérateur bind peut être utilisé pour aider à raccourcir les octets par rapport aux fonctions répétées:
De plus, si vous souhaitez utiliser la fonction avec un autre,
this
par exemple:la source
Éviter les virgules lors du stockage de nombreuses données
Si vous avez besoin de stocker beaucoup de données (index, caractères,…) dans un tableau, il vaudrait peut-être mieux laisser toutes les virgules à distance. Cela fonctionne mieux si chaque donnée a la même longueur de chaîne, 1 étant évidemment optimale.
43 octets (base)
34 octets (sans virgule)
Si vous êtes prêt à modifier votre accès au tableau , vous pouvez le réduire davantage en stockant les mêmes valeurs, comme ceci:
27 octets (mêmes données, ne modifie que l'accès au tableau)
la source