underscore react pick debounce javascript functional-programming underscore.js

javascript - react - Underscore.js: cómo encadenar funciones personalizadas



underscore lodash (7)

Usando Underscore.js , puedo escribir lo siguiente que devuelve 42 :

_([42, 43]).chain() .first() .value()

Tengo una función personalizada, no parte de Underscore.js llamada double() :

function double(value) { return value * 2; };

Me gustaría poder llamar a esta función en una cadena de guion bajo, como si fuera parte del guión bajo. Me gustaría escribir lo siguiente, que me gustaría devolver 84 :

_([42, 43]).chain() .first() .double() .value()

Esto no puede funcionar ya que el subrayado no define double() . Podría usar tap() como en:

_([42, 43]).chain() .first() .tap(double) .value()

Esto es válido, pero el tap aplica la función a su argumento y devuelve el argumento, no el resultado de la función. Así que me parece que necesitaría una especie de tap que devuelve el resultado de la función aplicada a su argumento. ¿Hay algo como esto en Underscore.js? ¿Me estoy perdiendo algo terriblemente obvio?


¿El map funciona para esto?

_([42, 43]).chain() .first() .map(double) .value()

editar

a partir de la documentación, parece que el map solo funcionaría si lo coloca antes de la llamada a:

_([42, 43]).chain() .map(double) .first() .value()


Al no encontrar un tap que devuelve el valor devuelto por la función se ejecuta, defino uno que puedo take y agregar a _ :

_.mixin({take: function(obj, interceptor) { return interceptor(obj); }});

Entonces asumiendo que tengo:

function double(value) { return value * 2; };

Puedo escribir:

_([42, 43]).chain() .first() // 42 .take(double) // Applies double to 42 .value() // 84

Puedes mirar take como map en objetos, en lugar de listas. ¿Quieres experimentar con esto? Vea este ejemplo en jsFiddle .


Así que tienes una función personalizada:

function double(value) { return value * 2; }

Puedes usar mixin para ampliar el guión bajo:

_.mixin({ double:double });

Ahora puedes llamar a tu función desde el objeto de subrayado _ :

_.double(42); // 84

y del objeto envuelto devuelto de chain :

_([42, 43]).chain() .first() .double() // double made it onto the wrapped object too .value(); // 84


Muchas formas de lograr esto fácilmente, aquí hay una de estas soluciones:

_.chain([42,43]) .first(1) .map(double) .first() .value(); // 84

Sin embargo, recomendaría el uso de Ramda ya que con auto-curry y pipe / componer este tipo de tareas son triviales:

R.pipe(R.head, R.multiply(2))([42, 43]); // 84 equivalent to: R.compose(R.multiply(2), R.head)([42, 43]); // 84

Si desea extender la solución a tomar, digamos los primeros 2 elementos, en lugar de un solo valor, como lo solicita el OP, entonces:

R.pipe(R.take(2), R.map(R.multiply(2)))([42, 43]) // [84, 86]

Sin embargo, en Ramda R.com se prefiere. De cualquier manera, para tareas triviales como esta, tiende a ser más conveniente y fácil de usar.


Muy bien, me acabo de leer el código fuente anotado de subrayado por primera vez. Pero creo que puedes hacer algo como esto:

function double(value) { return value * 2; }; var obj = _([42, 43]).addToWrapper({double:double}); obj.chain() .first() .double() .value();

La sintaxis / detalles pueden no ser correctos, pero el punto central es este: cuando llama a _([42,43]) , está llamando subrayado como una función. Cuando lo haces, crea una instancia de un nuevo objeto y luego se mezcla en ese objeto la mayoría de las funciones de subrayado. Entonces, te devuelve ese objeto. Luego puede agregar sus propias funciones a ese objeto, y nada de esto contamina el espacio de nombres "_".

Eso es lo que me pareció el código de subrayado.js. Si me equivoco, me gustaría averiguarlo y espero que alguien explique por qué.

EDITAR: De hecho, he estado usando underscore.js en gran medida durante aproximadamente un mes, y me he familiarizado bastante con él. Ahora sé que se comporta como dije aquí. Cuando llama a _ como una función de Constructor, recupera su propio "espacio de nombres" (solo un objeto), y puede agregarle cosas con addToWrapper () que se muestran en su espacio de nombres pero no en la "_" global " espacio de nombres. Así que la característica que quería el OP ya está incorporada. (Y me ha impresionado mucho el guión bajo, por cierto, está muy bien hecho).


Parece que lodash ha implementado exactamente lo que estás buscando:

_.thru(value, interceptor)

de los documentos:

Este método es como _.tap, excepto que devuelve el resultado del interceptor

https://lodash.com/docs#thru


Usar compose es otra forma de lidiar con la situación, pero creo que agregar una función como take como sugerí anteriormente es una mejor solución. Aún así, aquí es cómo se vería el código con compose :

function double(value) { return value * 2; }; _.compose( double, _.first, _.bind(_.identity, _, [42, 43]) )();

El valor inicial debe proporcionarse a través de una función que devuelve ese valor (aquí se hace mediante la identity ), y las funciones deben enumerarse en otra que sea la inversa de lo que tienes con una cadena, que parece bastante poco natural yo.