2012-04-17 4 views
11

El siguiente código funciona, y aunque entiendo por qué funciona, no lo he visto en ningún lado. Supongo que esto se debe a que todos los otros patrones de diseño son mucho mejores.add (1) (2) (3) .total === 6 - ¿Alguien más ha visto funciones autorregresivas usadas así?

Todavía esperaba ver el ejemplo como una advertencia en la línea, pero no lo hice.

Claro, es horrible, sobre todo con el ejemplo debajo de la cual he elegido porque está claro lo que hace, sino:

Lo que se llama este patrón?

¿Es de uso común?

¿Hay algún proyecto legítimo que utilice este patrón?

var add = function container (val) { 

    addFunc = function f (val, undefined) { 
    addFunc.total += val; 
    return addFunc; 
    }; 

addFunc.total = 0; 

return addFunc(val); 
}; 

alert(add(1)(2)(3).total); 
alert(add(1)(2)(33).total); 

Editar: Cambio de nombre de variable para que el código funcione en IE.

+1

Este patrón de diseño parece más un rompecabezas que un código limpio :) –

+2

¿Pero POR QUÉ harías algo así? –

+3

Este patrón no me parece terrible. Es muy claro para leer. Creo que prefiero ver el 'total' como una variable local, y la propiedad' .total' como un método que devuelve el resultado y restablece la variable. –

Respuesta

4

Técnicamente, esto podría considerarse encadenamiento o encapsulación.

Encadena cuando puede realizar un conjunto de operaciones indefinidamente fuera de una función original. jQuery usa una forma de esto cuando puede encadenar llamadas para establecer propiedades y atributos en un selector original. En esta situación, el creador quería poder encadenar llamadas para agregarlas sin tener que volver a escribir el nombre de la función. No es la más limpia de las ideas, sino válida.

Además, dado que el cuerpo real del código nunca se expone a la persona que llama, esto también podría considerarse una encapsulación, ya que el método addFunc no está expuesto al alcance externo.

+0

Soy el creador, realmente no lo creé con un propósito, es el resultado de un error tipográfico que limpié en un ejemplo de trabajo, pero el resto de lo que dijiste es perfecto. No esperaba haberlo hecho primero, por así decirlo, esperaba que tuviera un nombre, algo con pop, como "función anónima autoinvocada": hay un nombre que no olvidará. – user989370

+0

Olvidé: he visto el método de encadenamiento antes (y me gusta mucho en jQuery) y entiendo por qué funciona, principalmente intentaba entender por qué de esta manera y no de otra. – user989370

1

Usted sería infinitamente mejor con:

function add() { 
    var l = arguments.length, i, sum = 0; 
    for(i=0; i<l; i++) sum += arguments[i]; 
    return sum; 
} 
alert(add(1,2,3)); // 6 

Realmente, no debería haber ninguna razón para que el estilo de código que está preguntando por. No he visto ningún uso legitimado, solo longitud arbitraria arguments.

+0

Creo que la mejora más obvia es - 1 + 2 + 3. Obviamente, el ejemplo para el que lo utilicé es solo ilustración y no algo que alguien pueda hacer (¡espero!). Realmente no lo uso, y nunca lo he usado. – user989370

2

Esto se llama Currying wikipedia. Del nombre de Haskell Curry wikipedia (pero originalmente desarrollado por Moses Ilyich Schönfinkel wikipedia).

técnica de transformación de una función que toma múltiples argumentos (o una n-tupla de argumentos) de tal manera que se puede llamar como una cadena de funciones, cada una con un solo argumento (aplicación parcial).

De forma JavaScript Patterns 2010:

Cuándo utilizar currying - Cuando usted se encuentra llamando a la misma función y que pasa en su mayoría los mismos parámetros, entonces la función es probablemente un buen candidato para ganarse. Puede crear una nueva función de forma dinámica aplicando parcialmente un conjunto de argumentos a su función. La nueva función mantendrá los parámetros repetidos almacenados (para que no tenga que pasarlos cada vez) y los usará para completar previamente la lista completa de argumentos que espera la función original.

Otro article for currying de Dustin Diaz.

4

Este es un concepto de programación funcional llamado currying.

Esencialmente, dado un function foo(a, b, c) se crea un function bar(a) que devuelve function bar2(b) que devuelve function bar3(c) que da la respuesta final.

Técnicamente, esto no es cierto currying porque continúa infinitamente y utiliza un efecto secundario (la propiedad total) para salir del bucle infinito.

Pero en cualquier caso, puede haber aplicaciones útiles de este patrón. Es particularmente útil para atravesar estructuras de árbol en las que se calcula un resultado para cada hoja del árbol, donde el resultado depende de la ascendencia de esa hoja. Ejecuta la función curried en el nodo raíz, y luego ejecuta la función devuelta en cada nodo secundario, y luego para cada uno de esos nodos secundarios, etc. Una función curried pura devolvería otra función si el nodo en el que se ejecuta tiene hijos, y devolvería el valor deseado si ha alcanzado una hoja.

El código sería una función recursiva simple que pasa a sí misma un nuevo nodo "raíz" y la función para analizarlo, que siempre toma un argumento.

Pero, la forma en que se usa aquí parece más un ejercicio de aprendizaje que algo útil.

EDIT: Si quería hacer una función currificación pura pero todavía tienen la recursividad cuasi-infinito, los datos de entrada tiene que proporcionar la información de la parada (al igual que un C-secuencia utiliza el valor 0x00 para definir EOF):

var add = (function() { 
    var total = 0; 
    return function nextAdd(a) { 
     if(a != null) { 
      total += a; 
      return nextAdd; 
     } else { 
      return total; 
     } 
    }; 
})(); 

Entonces, add(1)(2)(3)(null) === 6 y no hay parámetro .total efecto secundario.

+0

Como todo el código puede reemplazarse con 1 + 2 + 3, definitivamente no debe usarse así, esto es solo para mostrar que realmente se ejecuta. – user989370

+0

Oye, acabo de agregar una versión de currificación pura del sumador para que puedas verla. –

+0

Gracias por el ejemplo: la parte total se atornillaba a mi ejemplo al final para mostrar que funcionaba, en realidad no estaba planificada. En general, iba por la velocidad con algo de legibilidad. Creo que voy a seguir investigando, ya que parece ser el lugar desde donde se pasó al código con un uso real. – user989370

Cuestiones relacionadas