2012-02-18 16 views
16

Tengo un montón de funciones útiles que he recopilado durante toda mi vida.Cómo encadenar funciones sin usar prototipos?

function one(num){ 
    return num+1; 
} 

function two(num){ 
    return num+2; 
} 

puedo llamar con two(two(one(5)))

Pero yo preferiría usar (5).one().two().two()

¿Cómo puedo lograr esto sin usar prototipo?

Traté de ver cómo funciona la cadena de subrayar, pero su código es demasiado intensa para entenderlo

+1

sólo para el registro, sí, esas son las funciones que he estado recopilando ... – mithril333221

Respuesta

22

La sintaxis con punto está reservado para los objetos. Así que usted puede hacer algo como

function MyNumber(n) { 
    var internal = Number(n); 
    this.one = function() { 
     internal += 1; 
     // here comes the magic that allows chaining: 
     return this; 
    } 
    // this.two analogous 
    this.valueOf = function() { 
     return internal; 
    } 
} 

new MyNumber(5).one().two().two().valueOf(); // 10 

O vas a poner en práctica estos métodos en el prototipo del objeto Number/función nativa. Eso permitiría (5).one()...

+0

Por supuesto, también debe implementar esa cosa 'MyNumber' con prototipos, porque es mucho más eficiente. – Bergi

+0

El 'valueOf()' es necesario ?, quiero decir, ¿debo terminar siempre mis encadenamientos con algún tipo de función que devuelva el valor? – mithril333221

+0

@ mithril333221 - para que el trabajo de encadenamiento, el valor de retorno de cada método DEBE ser un objeto del tipo correcto. Si quiere algo diferente a eso del objeto, debe llamar a un método para obtener esa información. – jfriend00

4

Una alternativa agradable y en general es la creación de una función de la composición de funciones personalizada

var go = function(x, fs){ 
    for(var i=0; i < fs.length; i++){ 
     x = fs[i](x); 
    } 
    return x; 
} 

Se le puede llamar así:

go(5, [one, two, two]) 

no soy personalmente un gran fan del método encadenando ya que lo restringe a un conjunto predefinido de funciones y existe una especie de desajuste de impedancia entre los valores dentro del "objeto de encadenamiento" y los valores libres externos.

+0

Quiero saber qué restricciones son – mithril333221

+0

Quiero decir que si quieres hacer un enfoque de" método de encadenamiento "necesitas saber qué es todo lo encadenable los métodos serán cuando defina el chainer (ya que necesita agregar un método al prototipo del chainer para cada función). Por otro lado, la versión de composición de funciones no necesita conocer las funciones de antemano para que pueda pasar lo que quiera – hugomg

+0

Aún así, puedes agregar funciones al prototipo cada vez que las necesites, el problema es que tienen que encajar en la construcción chainer con 'return this' y usar' this._value'. La desventaja de la composición es que una biblioteca contaminaría el espacio de nombres global, y un espacio de nombres para unirlos hace que la sintaxis de la composición sea más difícil. – Bergi

6

Para evitar tener que llamar al toValue al final de la cadena como en la solución de @ Bergi, puede usar una función con métodos adjuntos. JS llamará automáticamente al toValue cuando intente convertirlo en un tipo primitivo.

function MyNumber(n) { 
    function x() { } 
    x.one = function() { n++; return this; }; 
    x.valueOf = function() { return n; }; 
    return x; 
} 

Entonces,

MyNumber(5).one().one() 
> 7 
0

Otra alternativa es utilizar la función lodash flow. Por ejemplo:

var five = _.flow(one, two, two) 
five(5) 

Prefiero asignar una nueva cadena a una variable. Le da un nombre claro y fomenta la reutilización.

BTW, lodash también ayuda en el paso de argumentos adicionales para las funciones de la cadena. Por ejemplo:

var addFive = _.flow(
    _.partialRight(_.add, 1), 
    _.partialRight(_.add, 2), 
    _.partialRight(_.add, 2) 
) 

Hay muchas otras funciones útiles para ayudar en el encadenamiento funcional, por ejemplo, parcial, repartidas, flip, negate, etc.

Cuestiones relacionadas