Esto es similar a otros "Consejos para jugar golf en <...>", pero apunta específicamente a las funciones más nuevas en JavaScript presentadas en ECMAScript 6 y superiores.
JavaScript es un lenguaje inherentemente muy prolijo, function(){}
, .forEach()
, la conversión de cadena a la matriz, matriz de objeto similar a la matriz, etc, etc, son súper hincha y no es saludable para jugar al golf.
ES6 +, por otro lado, tiene algunas características súper prácticas y una huella reducida. x=>y
, [...x]
etc. son solo algunos de los ejemplos.
Por favor, publique algunos trucos agradables que pueden ayudar a eliminar esos pocos bytes adicionales de su código.
NOTA: Los trucos para ES5 ya están disponibles en Consejos para jugar golf en JavaScript ; Las respuestas a este hilo deben centrarse en trucos solo disponibles en ES6 y otras versiones futuras de ES.
Sin embargo, este hilo también es para usuarios que actualmente juegan golf usando las funciones de ES5. Las respuestas también pueden contener consejos para ayudarlos a comprender y asignar las funciones de ES6 a su estilo de codificación ES5.
fuente
Trucos aprendidos aquí desde que me uní
Mi lenguaje de programación principal es JS y principalmente ES6. Desde que me uní a este sitio hace una semana, he aprendido muchos trucos útiles de otros miembros. Estoy combinando algunos de esos aquí. Todos los créditos a la comunidad.
Funciones de flecha y bucles
Todos sabemos que las funciones de flecha guardan muchos byts
Pero debes tener en cuenta algunas cosas
,
ejemplo,(a=b,a.map(d))
- Aquí, el valor que se devuelve es la última expresióna.map(d)
do something
parte es más de una declaración, debe agregar los{}
corchetes circundantes .{}
corchetes circundantes , debe agregar una declaración de retorno explícita.Lo anterior es cierto muchas veces cuando tienes bucles involucrados. Entonces algo como:
Aquí estoy desperdiciando al menos 9 caracteres debido a la devolución. Esto puede ser optimizado.
.map
o.every
o en su.some
lugar. Tenga en cuenta que si desea cambiar la misma matriz que está mapeando, fallará.Entonces lo anterior se convierte en:
caracteres eliminados:
{}return
caracteres añadidos:
(){}>|
Tenga en cuenta cómo llamo al método de cierre, que llena correctamente la variable
n
y luego, dado que el método de cierre no devuelve nada (es decir, regresaundefined
), lo hago a bit o lo devuelvon
todo en una sola declaración de la función de flecha exterioru
Comas y punto y coma
Evítalos lo que sea,
Si está declarando variables en un bucle, o como se mencionó en la sección anterior, usando
,
declaraciones separadas para tener funciones de flecha de declaración única, entonces puede usar algunos trucos bastante ingeniosos para evitarlos,
o;
eliminar esos últimos bytes.Considera este código:
Aquí, estoy llamando a muchos métodos para inicializar muchas variables. Cada inicialización está usando un
,
o;
. Esto puede reescribirse como:Observe cómo uso el hecho de que el método no molesta a la variable que se le pasa y lo uso para reducir 3 bytes.
Misceláneos
.search
en lugar de.indexOf
Ambos dan el mismo resultado, pero
search
es más corto. Aunque la búsqueda espera una expresión regular, úsela sabiamente.`Cadenas de plantilla`
Estos son muy útiles cuando tiene que concatenar una o más partes de la cadena en función de ciertas condiciones.
Tome el siguiente ejemplo para generar una quine en JS
vs.
En una cadena de plantilla, que es una cadena dentro de dos comillas inversas (`), cualquier cosa dentro de a
${ }
se trata como un código y se evalúa para insertar la respuesta resultante en la cadena.Publicaré algunos trucos más tarde. ¡Feliz golf!
fuente
regexp
, no una cadena. Prueba'abc'.search('.')
.map
, la recursión es otra técnica que a veces puede ayudarlo a convertir unfor
bucle en una expresión.Usar shorthands de propiedad
Las abreviaturas de propiedad le permiten establecer variables a los valores de una matriz:
Esto también se puede usar como:
Incluso puede usar esto para revertir variables:
También puede usar esto para acortar
slice()
funciones.Conversiones base
ES6 proporciona una forma mucho más corta de convertir los formularios Base-2 (binario) y Base-8 (octal) a decimal:
+
se puede usar para convertir una cadena binaria, octal o hexadecimal a un número decimal. Se puede utilizar0b
,0o
y0x
, si es binario, octal y hexadecimal, respectivamente .:Si está usando esto> 7 veces, será más corto de usar
parseInt
y cambiarle el nombre:Ahora
p
se puede usar paraparseInt
ahorrar muchos bytes a largo plazo.fuente
'0x'+v-0
es incluso más corto, pero puede no funcionar tan bien en algunos escenarios.0767
(ES5) es más corto que la0o767
notación (ES6).0767
es una extensión no estándar y está explícitamente prohibida en modo estricto.0
los literales octales prefijados no van a ninguna parte, y son tan válidos como ecmascript0o
.Usar plantillas de cadena con funciones
Cuando tiene una función con una cadena como argumentos. Puede omitir el
()
si no tiene ninguna expresión:fuente
fun`string`
es lo mismo quefun(["string"])
nofun("string")
. Esto está bien para funciones que se convierten en cadenas, comoalert
, pero para otros esto podría causar problemas. Para obtener más información, consulte el artículo de MDNfun`foo${1}bar${2}baz
es equivalente a llamarfun(["foo","bar","baz"],1,2)
Comprensiones de matriz (Firefox 30-57)
Nota: las comprensiones de matriz nunca se estandarizaron y quedaron obsoletas con Firefox 58. Úselo bajo su propio riesgo.
Originalmente, la especificación ECMAScript 7 contenía un montón de nuevas características basadas en matrices. Aunque la mayoría de estos no llegaron a la versión finalizada, Firefox admite (ed) posiblemente la mayor de estas características: una nueva sintaxis elegante que puede reemplazar
.filter
y.map
confor(a of b)
sintaxis. Aquí hay un ejemplo:Como puede ver, las dos líneas no son tan diferentes, aparte de la segunda que no contiene las palabras clave voluminosas y las funciones de flecha. Pero esto solo explica el pedido
.filter().map()
; ¿Qué pasa si tienes en su.map().filter()
lugar? Realmente depende de la situación:O lo que si quieres , ya sea
.map
o.filter
? Bueno, por lo general resulta menos aceptable:Por lo tanto, mi consejo es usar las comprensiones de matriz donde sea que usas habitualmente
.map
y.filter
, pero no solo una u otra.Comprensiones de cuerdas
Lo bueno de las comprensiones de ES7 es que, a diferencia de las funciones específicas de la matriz como
.map
y.filter
, se pueden usar en cualquier objeto iterable, no solo en las matrices. Esto es especialmente útil cuando se trata de cadenas. Por ejemplo, si desea ejecutar cada carácterc
en una cadena a través dec.charCodeAt()
:Eso es dos bytes guardados en una escala bastante pequeña. ¿Y qué pasa si quieres filtrar ciertos caracteres en una cadena? Por ejemplo, este solo guarda letras mayúsculas:
Hmm, eso no es más corto. Pero si combinamos los dos:
¡Guau, un total de 10 bytes guardados!
Otra ventaja de la comprensión de cadenas es que las cadenas codificadas ahorran un byte adicional, ya que puede omitir el espacio después de
of
:Indexación
Las comprensiones de matriz hacen que sea un poco más difícil obtener el índice actual en la cadena / matriz, pero se puede hacer:
Lo principal a tener en cuenta es asegurarse de que el índice se incremente cada vez, no solo cuando se cumple una condición.
Generador de comprensiones
Las comprensiones de generador tienen básicamente la misma sintaxis que las comprensiones de matriz; simplemente reemplace los corchetes con paréntesis:
Esto crea un generador que funciona de la misma manera que una matriz, pero esa es una historia para otra respuesta.
Resumen
Básicamente, aunque las comprensiones son generalmente más cortas que
.map().filter()
, todo se reduce a los detalles de la situación. Es mejor intentarlo en ambos sentidos y ver cuál funciona mejor.PD ¡No dudes en sugerir otro consejo relacionado con la comprensión o una forma de mejorar esta respuesta!
fuente
(x,y)=>[...Array(y-x)].map(a=>x++)
x=>[...Array(x).keys()]
n=>[for(x of Array(n).keys())if(/1/.test(x))x]
(ahorra 7 bytes)Las expresiones de función en ES6 usan la notación de flecha, y ayuda mucho a ahorrar bytes si se compara con la versión ES5:
Si su función solo tiene un parámetro, puede omitir los paréntesis para guardar dos bytes:
Si su función no tiene ningún parámetro, declare como si tuviera uno para guardar un byte:
Cuidado: las funciones de flecha no son exactamente las mismas que
function () {}
. Las reglas parathis
son diferentes (y mejor IMO). Ver documentosfuente
this
etc.f=(...x)=>x
tendría esof(1,2,3) => [1,2,3]
.(x,y)=>...
, puede guardar un byte con curry reemplazándolo conx=>y=>...
Usando
eval
para funciones de flecha con múltiples declaraciones y unreturn
Uno de los trucos más ridículos que he encontrado ...
Imagine una función de flecha simple que necesita múltiples enunciados y a
return
.Una función simple que acepta un único parámetro
a
, que itera sobre todos los enteros[0, a)
y los pega al final de la cadena de salidao
, que se devuelve. Por ejemplo, llamar a esto4
como el parámetro produciría0123
.Tenga en cuenta que esta función de flecha tenía que estar envuelta en llaves
{}
, y tener unareturn o
al final.Este primer intento pesa 39 bytes .
No está mal, pero al usarlo
eval
, podemos mejorar esto.Esta función eliminó las llaves y la declaración de retorno envolviendo el código en un
eval
y simplemente haciendo la última declaración en laeval
evaluación parao
. Esto haceeval
que regreseo
, lo que a su vez hace que la función regreseo
, ya que ahora es una sola declaración.Este intento mejorado pesa 38 bytes , ahorrando un byte del original.
¡Pero espera hay mas! Las declaraciones de evaluación devuelven lo que evaluó su última declaración. En este caso,
o+=i
evalúa ao
, por lo que no necesitamos;o
! (¡Gracias, edc65!)Este intento final pesa solo 36 bytes , ¡un ahorro de 3 bytes sobre el original!
Esta técnica podría extenderse a cualquier caso general en el que una función de flecha necesita devolver un valor y tener múltiples declaraciones (que no podrían combinarse por otros medios)
se convierte
guardar un byte
Si se
statement2
evalúa comov
, esto puede serahorrando un total de 3 bytes.
fuente
;o
- pruébelo:a=>eval('for(o="",i=0;i<a;i++)o+=i')
Prefiere cadenas de plantilla nuevas líneas sobre "\ n"
Esto comenzará a dar sus frutos incluso en un nuevo carácter de línea en su código. Un caso de uso podría ser:
(16 bytes)
(15 bytes)
Actualización: Incluso puede dejar de lado las llaves debido a las cadenas de plantillas etiquetadas (¡gracias, edc65!):
(13 bytes)
fuente
Relleno de matrices: valores estáticos y rangos dinámicos
Originalmente los dejé como comentarios bajo comprensión, pero dado que esa publicación se centró principalmente en las comprensiones, pensé que sería bueno darle a este su propio lugar.
ES6 nos dio la capacidad de llenar matrices con valores estáticos sin el uso de bucles:
Ambos devuelven una matriz de longitud x, llena con el valor 0.
Sin embargo, si desea llenar matrices con valores dinámicos (como un rango de 0 ... x), el resultado es un poco más largo (aunque aún más corto que la forma anterior):
Ambos devuelven una matriz de longitud x, comenzando con el valor 0 y terminando en x-1.
La razón por la que necesita la entrada
.fill()
es porque simplemente inicializar una matriz no le permitirá mapearla. Es decir, hacerx=>Array(x).map((a,i)=>i)
devolverá una matriz vacía. También puede evitar la necesidad de relleno (y, por lo tanto, hacerlo aún más corto) utilizando el operador de propagación de la siguiente manera:Usando el operador de propagación y la
.keys()
función, ahora puede hacer un corto rango de 0 ... x:Si desea un rango personalizado de x ... y, o un rango especializado por completo (como números pares), puede deshacerse de él
.keys()
y simplemente usarlo.map()
o usarlo.filter()
con el operador de propagación:fuente
x=>Array(x).fill(i=0).map(a=>i++)
Además, no estoy seguro de que el 0.fill(0)
sea necesario. ¿Lo has probado sin?a=>a%2-1
funciona bien, al igual quea=>a%2<1
.[...Array(x)]
funciona igual de bienArray(x).fill()
y es 2 bytes más corto.x=>[...Array(x)].map((a,i)=>i)
1/4
ejemplo se escribiría más[0,0,0,0]
brevemente y 2) las funciones en cadena son específicas de la implementación, por lo que no devolverán una longitud confiable (Map
es 32 bytes en Chrome, pero 36 bytes en Firefox).Valores devueltos en funciones de flecha
Es de conocimiento común que si una sola declaración sigue la declaración de la función de flecha, devuelve el resultado de esa declaración:
-7 bytes
Entonces, cuando sea posible, combine varias declaraciones en una. Esto se hace más fácilmente rodeando las declaraciones con paréntesis y separándolas con comas:
-8 bytes
Pero si solo hay dos declaraciones, generalmente es posible (y más corto) combinarlas con
&&
o||
:-9 bytes
Finalmente, si está utilizando un mapa (o similar) y necesita devolver un número y puede garantizar que el mapa nunca devolverá una matriz de 1 longitud con un número, puede devolver el número con
|
:fuente
Hacks aleatorios de cadenas de plantillas
Esta función rifla dos cadenas (es decir, se convierte
"abc","de"
en"adbec"
):Tenga en cuenta que esto solo funciona cuando
x
es más largo quey
. ¿Cómo funciona, preguntas?String.raw
está diseñado para ser una etiqueta de plantilla, así:Esto básicamente llama
String.raw(["x: ", "\ny: ", "\nx + y: ", ""], x, y, x + y)
, aunque no es tan simple. La matriz de plantillas también tiene unaraw
propiedad especial , que es básicamente una copia de la matriz, pero con las cadenas sin formato.String.raw(x, ...args)
básicamente regresax.raw[0] + args[0] + x.raw[1] + args[1] + x.raw[2] + ...
y así sucesivamente hasta que sex
acaben los artículos.Entonces, ahora que sabemos cómo
String.raw
funciona, podemos usarlo para nuestra ventaja:Por supuesto, para el último,
f=(x,y)=>x.split``.join(y)
es mucho más corto, pero entiendes la idea.Aquí hay un par de funciones de riffling que también funcionan si
x
yy
son de igual longitud:Puede obtener más información
String.raw
sobre MDN .fuente
Cómo jugar al golf con recursión
La recursión, aunque no es la opción más rápida, es a menudo la más corta. En general, la recursividad es más corta si la solución puede simplificarse a una parte más pequeña del desafío, especialmente si la entrada es un número o una cadena. Por ejemplo, si
f("abcd")
se puede calcular a partir de"a"
yf("bcd")
, generalmente es mejor usar la recursividad.Tomemos, por ejemplo, factorial:
En este ejemplo, la recursividad es obviamente mucho más corta que cualquier otra opción.
¿Qué tal la suma de los códigos de barras:
Este es más complicado, pero podemos ver que cuando se implementa correctamente, la recursión ahorra 4 bytes
.map
.Ahora veamos los diferentes tipos de recursividad:
Pre-recursividad
Este suele ser el tipo de recursión más corto. La entrada se divide en dos partes
a
yb
, y la función calcula algo cona
yf(b)
. Volviendo a nuestro ejemplo factorial:En este caso,
a
es n ,b
es n-1 y el valor devuelto esa*f(b)
.Nota importante: Todas las funciones recursivas deben tener una forma de detener el recursivo cuando la entrada es lo suficientemente pequeña. En la función factorial, esto se controla con
n? :1
, es decir, si la entrada es 0 , devuelve 1 sinf
volver a llamar .Post-recursión
La post-recursión es similar a la pre-recursión, pero ligeramente diferente. La entrada se divide en dos partes
a
yb
, y la función calcula algo cona
, luego llamaf(b,a)
. El segundo argumento generalmente tiene un valor predeterminado (es decirf(a,b=1)
).La pre-recursión es buena cuando necesitas hacer algo especial con el resultado final. Por ejemplo, si desea el factorial de un número más 1:
Aun así, sin embargo, post- no siempre es más corto que usar pre-recursión dentro de otra función:
Entonces, ¿cuándo es más corto? Puede notar que la post-recursión en este ejemplo requiere paréntesis alrededor de los argumentos de la función, mientras que la pre-recursión no. Generalmente, si ambas soluciones necesitan paréntesis alrededor de los argumentos, la post-recursión es alrededor de 2 bytes más corta:
(Programas tomados de esta respuesta )
Cómo encontrar la solución más corta
Por lo general, la única forma de encontrar el método más corto es probarlos todos. Esto incluye:
.map
(para cadenas, ya sea[...s].map
os.replace
; para números, puede crear un rango )Y estas son solo las soluciones más comunes; La mejor solución podría ser una combinación de estos, o incluso algo completamente diferente . La mejor manera de encontrar la solución más corta es probarlo todo .
fuente
Maneras más cortas de hacer
.replace
Si desea reemplazar todas las instancias de una subcadena exacta con otra en una cadena, la forma obvia sería:
Sin embargo, puede hacer 1 byte más corto:
Tenga en cuenta que esto ya no es más corto si desea utilizar cualquier función de expresiones regulares además del
g
indicador. Sin embargo, si está reemplazando todas las instancias de una variable, generalmente es mucho más corta:A veces querrás mapear cada carácter en una cadena, reemplazando cada uno con algo más. A menudo me encuentro haciendo esto:
Sin embargo,
.replace
casi siempre es más corto:Ahora, si desea mapear cada carácter en una cadena pero no le importa la cadena resultante,
.map
generalmente es mejor porque puede deshacerse de.join``
:fuente
/\w/g
están interesados ciertos caracteres que coinciden con una expresión regular (me gusta ), entonces usar reemplazar será mucho mejor como en esta demostración .Escribir literales RegEx con
eval
El constructor de expresiones regulares puede ser muy voluminoso debido a su nombre largo. En cambio, escriba un literal con eval y backticks:
Si la variable
i
es igual afoo
, esto generará:Esto es igual a:
También puede usar
String.raw
para evitar tener que escapar repetidamente barras inclinadas\
Esto generará:
Que es igual a:
¡Tenga en cuenta!
String.raw
ocupa muchos bytes y, a menos que tenga al menos nueve barras invertidas,String.raw
será más largo.fuente
new
allí, por lo que usar el constructor es realmente más corto para el segundo ejemplo.forEach
vsfor
buclesSiempre prefiera
.map
cualquier para el bucle. Ahorro fácil e instantáneo.fuente
Uso de contadores no inicializados en recursividad
Nota : Estrictamente hablando, esto no es específico para ES6. Sin embargo, tiene más sentido usar y abusar de la recursividad en ES6, debido a la naturaleza concisa de las funciones de flecha.
Es bastante común encontrar una función recursiva que utiliza un contador
k
inicialmente establecido en cero e incrementado en cada iteración:Bajo ciertas circunstancias, es posible omitir la inicialización de dicho contador y reemplazarlo
k+1
con-~k
:Este truco generalmente ahorra 2 bytes .
¿Por qué y cuándo funciona?
La fórmula que lo hace posible es
~undefined === -1
. Entonces, en la primera iteración,-~k
se evaluará a1
. En las próximas iteraciones,-~k
es esencialmente equivalente a lo-(-k-1)
que es igualk+1
, al menos para enteros en el rango [0 ... 2 31 -1].Sin embargo, debe asegurarse de que tener
k = undefined
en la primera iteración no interrumpirá el comportamiento de la función. Debe tener especialmente en cuenta que la mayoría de las operaciones aritméticas involucradasundefined
resultarán enNaN
.Ejemplo 1
Dado un número entero positivo
n
, esta función busca el número entero más pequeñok
que no se dividen
:Se puede acortar a:
Esto funciona porque
n % undefined
esNaN
, lo cual es falso. Ese es el resultado esperado en la primera iteración.[Enlace a la respuesta original]
Ejemplo # 2
Dado un entero positivo
n
, esta función busca un enterop
tal que(3**p) - 1 == n
:Se puede acortar a:
Esto funciona porque
p
no se usa en absoluto en la primera iteración (n<k
siendo falso).[Enlace a la respuesta original]
fuente
Funciones ES6
Matemáticas
Math.cbrt(x)
guarda caracteres queMath.pow(x,1/3)
.3 caracteres guardados
Math.hypot(...args)
es útil cuando necesitas la raíz cuadrada de la suma de los cuadrados de los argumentos. Hacer que el código ES5 haga eso es mucho más difícil que usar un incorporado.La función
Math.trunc(x)
no sería útil, ya quex|0
es más corta. (¡Gracias Mwr247!)Hay muchas propiedades que requieren mucho código en ES5, pero son más fáciles en ES6:
Math.acosh
,asinh
,atanh
,cosh
,sinh
,tanh
. Calcula el equivalente hiperbólico de las funciones trigonométricas.Math.clz32
. Podría ser posible hacerlo en ES5, pero ahora es más fácil. Cuenta los ceros a la izquierda en la representación de 32 bits de un número.Hay mucho más, así que sólo voy a enumerar algunas:
Math.sign
,Math.fround
,Math.imul
,Math.log10
,Math.log2
,Math.log1p
.fuente
Math.trunc(x)
es cuatro veces más largo quex|0
.Math.hypot(a,b) => Math.sqrt(a*a+b*b)
(3 bytes más; se alarga aún más con más argumentos),Math.sign(a) => (a>0)-(a<0)
(1 byte más corto, pero necesita paréntesis circundantes en algunos casos; puede no funcionarNaN
)Optimización de pequeños rangos constantes para
map()
Contexto
map()
for
puede ser reemplazado por:
o más comúnmente:
Array(N)
NB : no se cuenta la longitud del código de devolución de llamada
F(i)
.Optimizaciones sin contador
NB : no se cuenta la longitud del código de devolución de llamada
F()
.fuente
2**26
ser2**29
?.keys()
, no necesitas un lambda:[...Array(10).keys()].map(do_something_with)
Desestructuración de tareas
ES6 presenta una nueva sintaxis para las tareas de desestructuración, es decir, cortar un valor en piezas y asignar cada pieza a una variable diferente. Aquí están algunos ejemplos:
Cadenas y matrices
Objetos
Estas asignaciones también se pueden usar en parámetros de función:
fuente
Otra forma de evitar
return
Sabes que debes usar eval para las funciones de flecha con múltiples declaraciones y un retorno . En algunos casos inusuales, puede ahorrar más utilizando una subfunción interna.
Digo inusual porque
El resultado devuelto no debe ser la última expresión evaluada en el bucle.
Debe haber (al menos) 2 inicializaciones diferentes antes del ciclo
En este caso, puede utilizar una subfunción interna sin retorno, pasando uno de los valores iniciales como parámetro.
Ejemplo Encuentre el recíproco de la suma de la función exp para valores en un rango de a a b.
El largo camino - 55 bytes
Con eval - 54 bytes
Con una función interna - 53 bytes
Tenga en cuenta que sin el requisito de un límite de rango inferior
a
, puedo fusionar las inicializaciones de i y r y la versión de evaluación es más corta.fuente
a
(i,b)=>{for(r=0;i<=b;i++)r+=Math.exp(i);return 1/r}
return a/r
sería un mejor ejemplo(a,b)=>1/eval("for(r=0,i=a;i<=b;i++)r+=Math.exp(i)")
y en este caso(i,b)=>1/eval("for(r=0;i<=b;)r+=Math.exp(i++)")
Uso de la sintaxis de curry para funciones diádicas y recursivas
Funciones diádicas
Cada vez que una función toma exactamente dos argumentos sin valores predeterminados, el uso de la sintaxis de curry guarda un byte.
antes de
Llamado con
f(a,b)
Después
Llamado con
f(a)(b)
Nota : Esta publicación en Meta confirma la validez de esta sintaxis.
Funciones recursivas
El uso de la sintaxis de curry también puede ahorrar algunos bytes cuando una función recursiva toma varios argumentos, pero solo necesita actualizar algunos de ellos entre cada iteración.
Ejemplo
La siguiente función calcula la suma de todos los enteros en el rango
[a,b]
:Debido a que
a
permanece sin cambios durante todo el proceso, podemos guardar 3 bytes usando:Nota : Como notó Neil en los comentarios, el hecho de que un argumento no se pase explícitamente a la función recursiva no significa que deba considerarse inmutable. Si es necesario, podríamos modificar
a
dentro del código de función cona++
,a--
o cualquier sintaxis similar.fuente
a=>F=b=>a>b?0:a+++F(b)
, modificandoa
para cada llamada recursiva. Esto no ayuda en ese caso, pero podría guardar bytes en casos con más argumentos.Función de prueba de primalidad
La siguiente función de 28 bytes devuelve
true
números primos y númerosfalse
no primos:Esto se puede modificar fácilmente para calcular otras cosas. Por ejemplo, esta función de 39 bytes cuenta el número de primos menor o igual que un número:
Si ya tiene una variable
n
que desea verificar para primalidad, la función de primalidad se puede simplificar bastante:Cómo funciona
Nota: Esto fallará con un error de "demasiada recursividad" cuando se llama con una entrada suficientemente grande, como 12345. Puede solucionar esto con un bucle:
fuente
x==1
Probablemente seax<2
para ahorrar.1
o0
(porquex
sería0
o-1
, respectivamente)!~-x
para -0 bytes.Array#concat()
y el operador de propagaciónEsto depende en gran medida de la situación.
Combinando múltiples matrices.
Prefiere la función concat a menos que la clonación.
0 bytes guardados
3 bytes desperdiciados
3 bytes guardados
6 bytes guardados
Prefiere usar una matriz ya existente para
Array#concat()
.Fácil 4 bytes guardados
fuente
Devuelve el resultado intermedio
Sabe que con el operador de coma puede ejecutar una secuencia de expresiones que devuelven el último valor. Pero al abusar de la sintaxis de la matriz literal, puede devolver cualquier valor intermedio. Es útil en .map () por ejemplo.
fuente
.join('')
puede ser.join``
Establecer valores predeterminados de parámetros de función
Este es realmente útil ...
Sin embargo, asegúrese de comprender que algo así
_=>_||'asdf'
es más corto cuando solo pasa un argumento (útil) a la función.fuente
_=>_||'asdf'
generalmente es más corto en la mayoría de los casos"asdf"
una entrada de""
(cadena vacía).undefined
, incluso si pasa explícitamente ese valor. Por ejemplo,[...Array(n)].map((a,b,c)=>b)
siempre pasaundefined
pora
, y por lo tanto puede proporcionarle un valor predeterminado (aunque no en términos deb
).Use en
eval
lugar de llaves para las funciones de flechaLas funciones de flecha son increíbles. Toman la forma
x=>y
, dondex
es un argumento yy
es el valor de retorno. Sin embargo, si necesita usar una estructura de control, comowhile
, tendría que poner llaves, por ejemplo=>{while(){};return}
. Sin embargo, podemos evitar esto; Afortunadamente, laeval
función toma una cadena, evalúa esa cadena como código JS y devuelve la última expresión evaluada . Por ejemplo, compare estos dos:Podemos usar una extensión de este concepto para acortar aún más nuestro código: a los ojos de
eval
, las estructuras de control también devuelven su última expresión evaluada. Por ejemplo:fuente
Operaciones lógicas de golf en ES6
"GLOE (S6)"
Lógica general
Digamos que ha construido declaraciones
s
yt
. Vea si puede usar alguno de los siguientes reemplazos:(Es posible que no funcionen si el orden es incorrecto; es decir,
+
y*
tienen una prioridad de orden menor que||
y&&
).Además, aquí hay algunas expresiones lógicas útiles:
s
ot
es verdad / XOR:s^t
s
yt
son el mismo valor de verdad:!s^t
os==t
Lógica de matriz
Todos los miembros de
a
satisfacer condiciónp
:Al menos un miembro de la
a
condición satisfacep
:Ningún miembro de
a
la condición satisfacenp
:!a.some(p)
.El elemento
e
existe en la matriza
:Elemento
e
no no existe en arraya
:fuente
&&
y||
comox?y:x
yx?x:y
, respectivamente. Pero puedo ver cómo esto sería útil en más programas basados en la lógica. El único problema con+
sería que por ejemplo,3
y-3
son a la vez Truthy, pero3+-3
no lo es.-
También podría funcionar, sis != t
.a.filter(t=>t==e).length==a.length
Es incorrecto. Debería ser!a.filter(t=>t==e).length
Acortar llamadas a funciones repetidas
Si ha repetido llamadas a una función con un nombre largo, como la manipulación del lienzo:
La forma tradicional de acortarlo sería alias el nombre de la función:
Si tiene suficientes llamadas, una mejor manera es crear una función que haga el trabajo por usted:
Si la mayoría de las llamadas a funciones están encadenadas, puede hacer que la función se devuelva, lo que le permite cortar dos bytes de cada llamada sucesiva:
Ejemplo de uso: 1 , 2
fuente
(l=::c.lineTo)(0,100)(100,100)(100,0)(0,0);c.stroke()
c.lineTo
que no se devuelve naturalmente)Operador de enlace
::
El operador de enlace se puede usar para ayudar a acortar bytes sobre funciones repetidas:
Además, si desea utilizar la función con un
this
ejemplo diferente, por ejemplo:fuente
Evitar comas al almacenar muchos datos
Si tiene muchos datos (es decir, índices, caracteres, ...) que necesita almacenar en una matriz, es mejor que deje todas las comas. Esto funciona mejor si cada dato tiene la misma longitud de cadena, 1 obviamente es óptimo.
43 bytes (línea de base)
34 bytes (sin comas)
Si está dispuesto a cambiar su acceso a la matriz , puede reducir esto aún más, almacenando los mismos valores de la siguiente manera:
27 bytes (mismos datos, solo cambia el acceso a la matriz)
fuente