
Según algunas encuestas , las funciones de flecha anónimas en JavaScript son la característica más popular de ES-2015, que también se destaca por la gran cantidad de tutoriales en Internet. Sin lugar a dudas, son muy útiles, pero en este breve artículo veremos ejemplos de cómo usar expresiones privadas de atención al menos maravillosas con funciones con nombre : NFE.
Ayuda corta
Expresión de funciones con nombre : una extensión de expresiones funcionales en JavaScript que le permite nombrar una función creada como parte de una expresión ( FunctionExpression ):
let fe = function named(...) { };
El punto es que dentro de la función referenciada por la variable fe , hay acceso a la función en sí a través del nombre nombrado . ¡Es imposible reescribir el nombre solo desde adentro!
Como usarlo
Por ejemplo, necesitamos escribir una función de decoración que contará el número de llamadas a alguna función. Esto se puede hacer con bastante elegancia con NFE:
const count = f => function df() { df.calls = (df.calls || 0) + 1; return f(...arguments); };
Aquí tenemos acceso a la función df devuelta, de modo que cuando se llama, guardamos el contador en la propiedad de llamadas , que estará disponible para leer si es necesario:
const csum = count((x, y) => x + y); csum(5, 10);
O guarde todos los resultados de la llamada a la función:
const accum = f => function df() { let res = f(...arguments); (df.results = (df.results || [])).push(res); return res; };
En cualquier caso, aprovechamos el hecho de que una función en JavaScript es un objeto, y podemos complementarla con las propiedades necesarias en nuestras tareas locales.
Obviamente, podemos llamar a una función. Usar NFE para la recursividad es especialmente agradable. Supongamos que queremos encontrar el enésimo miembro de la secuencia de Fibonacci (por alguna razón, todos quieren esto tarde o temprano):
const rf = function getfn(n) { return n > 2 ? getfn(n - 2) + getfn(n - 1) : 1; }; rf(1);
No vale la pena prestar atención a "colas" aquí. Pero sobre la capacidad de hacer lo mismo a través de FunctionDeclaration , sí. Pero la función de expresión tiene una ventaja: si desea transferir la función de rf a otra variable, no necesita editar la llamada recursiva en su interior.
Un buen ejemplo de una implementación de temporizador:
const ping = (callback, t) => setTimeout(function pf() { callback(); setTimeout(pf, t); }, t);
Aquí usamos NFE como literal como argumento en lugar de declarar una variable innecesaria. ¿Por qué no establecer Intervalo ? En lugar de una devolución de llamada, aquí puede haber una espera para una resolución de la promesa antes del próximo tic del temporizador.
Un ejemplo interesante sería la combinación de NFE y IIFE ( Expresión de función invocada inmediatamente ), cuando está en su lugar solo se necesita el resultado de la función recursiva. Solo una vez:
let data = { f10: function fact(n) { return n > 1 ? n * fact(n - 1) : 1; }(10) }; data.f10;
Es asi? bueno, aquí está el verdadero problema: hay una función f estrictamente creciente que actúa en el conjunto de números naturales. Encuentre el punto extremo x en el que el valor de la función no excede el y dado. Un ejemplo de tal función sería f(x) = 3 * x + 5
o f(x) = 2^x + 11
.
const find = (f, y) => function bs(a, b) { if (a + 1 === b) return a; let m = Math.ceil((a + b) / 2); return f(m) <= y ? bs(m, b) : bs(a, m); }(-1, y + 1); find(x => 3 * x + 5, 200);
No entraremos en detalles matemáticos. Considere la implementación:
- La función de búsqueda requerida tiene dos de nuestros parámetros f, y y devuelve el resultado de IIFE.
- Una función llamada instantáneamente implementa una búsqueda binaria de una solución, la primera llamada obtiene el rango inicial.
- La búsqueda en sí se implementa a través de la recursividad, que utiliza el nombre NFE para llamadas posteriores. No declaramos una función de búsqueda y no creamos una nueva variable.
Por supuesto, un problema similar se puede resolver a través de un ciclo simple con una condición previa, pero esto es demasiado imprescindible para la codificación de la consola.
Finalmente, algunas palabras sobre el seguimiento de la pila. Tenemos alguna función NFE, en cuyo cuerpo se produjo una excepción:
const fe = function named() { throw new Error('Something went wrong'); };
Como tenemos una función con nombre en la expresión, la veremos en el seguimiento de la pila:
Uncaught Error: Something went wrong at named (<anonymous>:2:11)
Sin embargo, a partir de ES-2015, muchas expresiones de funciones anónimas realmente crean una función con un nombre, sacándola de contexto:
const unnamed = function() { throw new Error('Something went wrong'); };
La función en el lado derecho de la expresión está asociada con la variable de la izquierda:
Uncaught Error: Something went wrong at unnamed (<anonymous>:2:7)
Pero esto no siempre es posible. Un ejemplo clásico es la inicialización de un script de biblioteca externa a través de IIFE, como una opción:
;(function() {
O un ejemplo frecuente de una función que devuelve otra función:
const bind = (f, ctx) => function() { return f.apply(ctx, arguments); };
No hay variable para la salida, por lo que en caso de una excepción veremos anónimo . NFE puede ayudar un poco en los litigios.
Breve conclusión
NFE es bueno para escribir código conciso y sin soporte para crear rápidamente prototipos de una amplia gama de tareas. Para usar su belleza en el código final, debes pensar un par de veces: JavaScript ya está sobrecargado con especificaciones interesantes.