Pregunta

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

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

He función personalizada, que no forma parte de la llamada Underscore.js double():

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

Me gustaría ser capaz de llamar a esta función en una cadena de subrayado, como si fuera parte de un guión bajo. Me gustaría escribir lo siguiente, que me gustaría 84 de retorno:

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

Esto no puede trabajar desde subrayado no define double(). Podría usar tap() como en:

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

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

¿Fue útil?

Solución

Al no encontrar un tap que devuelve el valor vuelve por la función es carreras, que definen una que puedo take y añadir a _:

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

A continuación, suponiendo que tengo:

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

Puedo escribir:

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

Se puede mirar a take como map en los objetos, en lugar de las listas. ¿Quieres experimentar con esto? Vea este ejemplo en jsFiddle .

Otros consejos

Así que tiene una función personalizada:

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

Se puede usar mixin extender subrayado con ella:

_.mixin({ double:double });

Ahora usted puede llamar a la función del objeto _ Subrayado:

_.double(42); // 84

y desde el objeto envuelto de regresar de chain:

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

Bien, estoy recién salido de la lectura del código fuente subrayado anotada por primera vez. Pero creo que se puede hacer algo como esto:

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

var obj = _([42, 43]).addToWrapper({double:double});

obj.chain()
  .first()
  .double()
  .value();

La sintaxis / datos puede que no sea correcto, pero el punto central es la siguiente: cuando se llama _([42,43]), que está llamando subrayado como una función. Al hacerlo, se crea una instancia de un nuevo objeto y mezclas entonces en ese objeto de la mayor parte de las funciones de subrayado. A continuación, devuelve ese objeto para ti. A continuación, puede añadir sus propias funciones para ese objeto, y nada de esto contamina el "_" espacio de nombres en sí.

Eso es lo que el código underscore.js miraban como a mí. Si estoy equivocado, me gustaría averiguar y es de esperar que alguien a explicar por qué.

EDIT: De hecho, he estado usando underscore.js en gran medida por alrededor de un mes, y he conseguido bastante familiarizado con él. Ahora saber se comporta como he dicho aquí. Cuando se llama _ como una función constructora, a recuperar su propio "espacio de nombres" (sólo un objeto), y se puede añadir cosas a ella con addToWrapper () que aparece en el espacio de nombres pero no en el "global" "_" espacio de nombres. Por lo que la función de la OP quisiera saber ya está integrada. (Y he estado muy impresionado con el guión bajo, por cierto, es muy muy bien hecho).

Muchas maneras de lograr esto fácilmente, aquí es una solución de este tipo:

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

Sin embargo, yo recomendaría usar Ramda continuación, con auto-curry y tubería / componen estos 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 quieres ampliar la solución para sacar decir los 2 primeros artículos, en lugar de un único valor, según lo solicitado por el PO, a continuación:

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

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

Las apariencias como lodash ha implementado exactamente lo que busca:

_.thru(value, interceptor)

a partir de los documentos:

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

https://lodash.com/docs#thru

Cómo funciona la map para esto?

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

editar

de la documentación, se ve como lo haría map único trabajo si se coloca antes de la llamada a first:

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

El uso de compose es otra manera de hacer frente a la situación, pero creo que la adición de una función como take como he sugerido anteriormente es una solución mejor. Sin embargo, aquí es cómo el código se vería con compose:

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

_.compose(
    double,
    _.first,
    _.bind(_.identity, _, [42, 43])
)();

El valor inicial debe ser proporcionada a través de una función que devuelve ese valor (en este caso realizada por currying identity), y las funciones deben ser enumeradas de otro, que es lo contrario de lo que tienes con una cadena, que aparece como muy poco natural para mí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top