2008-12-16 9 views
85

Possible en double:
How can I pre-set arguments in JavaScript function call? (Partial Function Application)Comment passer une référence à une fonction, avec des paramètres?

Je dois pouvoir passer une référence à une fonction avec un ensemble de paramètres.

Voici un exemple de passer une référence sans paramètres:

var f = function() { 
    //Some logic here... 
}; 

var fr = f; //Here I am passing a reference to function 'f', without parameters 
fr(); //the 'f' function is invoked, without parameters 

Maintenant, ce que je dois faire est de passer la même fonction f, mais cette fois je aurais besoin de passer des paramètres à la référence. Maintenant, je peux le faire avec une fonction anonyme et appeler la fonction f avec des paramètres dans la fonction nouvellement créée, comme par exemple:

var f = function() { 
     //Some logic here... 
    }; 

var fr = function (pars) { 
    f(pars); 
}; //Here I am creating an anonymous function, and invoking f inside it 

fr({p : 'a parameter'}); //Invoking the fr function, that will later invoke the f function with parameters 

Mais ma question est, est-il un moyen de passer une référence directe à la f fonction Avec les paramètres à fr, mais sans l'enfermer dans une fonction anonyme?

Que dois-je attribuer à fr pour le rendre invocable sans paramètres (fr()), de sorte que f (1,2,3) est exécutée lorsque fr est invoquée?

[UPDATE] J'ai suivi la réponse de Jason Bunting à here sur le Fonction partielle et la fonction JavaScript il des messages, il est exactement ce que je cherchais. Voici la solution:

function partial(func /*, 0..n args */) { 
    var args = Array.prototype.slice.call(arguments).splice(1); 
    return function() { 
    var allArguments = args.concat(Array.prototype.slice.call(arguments)); 
    return func.apply(this, allArguments); 
    }; 
} 
+0

Pour une raison quelconque, j'ai eu des ennuis avec la première instruction (var args = Array.prototype.slice.call (arguments) .splice (1);) et a dû utiliser à la place: var args = new Array(); pour (var i = 1; i

+0

juste au cas où quelqu'un aurait besoin de ceci: 'Function.prototype.pass = function() { var args = arguments, func = this; return function() {func.apply (this, args);} }; ' –

Répondre

77

Ce que vous AFTER est appelé application de fonction partielle. Ne pas se laisser berner par ceux qui ne comprennent pas la différence subtile entre cela et currying, ils sont différent.

L'application de fonction partielle peut être utilisée pour mettre en œuvre, mais n'est pas en cours d'exécution. Voici une citation de a blog post on the difference:

Lorsque l'application partielle prend une fonction et il en construit une fonction qui prend moins d'arguments, curryfication construit des fonctions qui prennent de multiples arguments par la composition des fonctions qui prennent chacun un seul argument.

Cela a déjà répondu, voir cette question pour votre réponse: How can I pre-set arguments in JavaScript function call?

Exemple:

var fr = partial(f, 1, 2, 3); 

// now, when you invoke fr() it will invoke f(1,2,3) 
fr(); 

Encore une fois, voir cette question pour les détails.

+0

Que dois-je affecter à' fr' pour le rendre invocable sans paramètres ('fr()'), de sorte que f (1 , 2,3) est exécuté lorsque 'fr' est invoqué –

+4

Note pour les futurs lecteurs, assurez-vous d'inclure la fonction' partial' fournie par Jason dans [son autre réponse] (http://stackoverflow.com/a/321527/ 1366033) – KyleMit

+2

Comme alternative à la fonction 'partial' de Jason, la bibliothèque [UnderscoreJS] (http://underscorejs.org) offre également une fonction' _.partial'. – sfletche

-4

Ce qui suit est équivalent à votre deuxième bloc de code:

var f = function() { 
     //Some logic here... 
    }; 

var fr = f; 

fr(pars); 

Si vous voulez passer en fait une référence à une fonction à une autre fonction, vous pouvez faire quelque chose comme ceci:

function fiz(x, y, z) { 
    return x + y + z; 
} 

// elsewhere... 

function foo(fn, p, q, r) { 
    return function() { 
     return fn(p, q, r); 
    } 
} 

// finally... 

f = foo(fiz, 1, 2, 3); 
f(); // returns 6 

Vous êtes certainement mieux d'utiliser un cadre pour ce genre de chose, cependant.

2

Vous pouvez également surcharger le prototype de fonction:

// partially applies the specified arguments to a function, returning a new function 
Function.prototype.curry = function() { 
    var func = this; 
    var slice = Array.prototype.slice; 
    var appliedArgs = slice.call(arguments, 0); 

    return function() { 
     var leftoverArgs = slice.call(arguments, 0); 
     return func.apply(this, appliedArgs.concat(leftoverArgs)); 
    }; 
}; 

// can do other fancy things: 

// flips the first two arguments of a function 
Function.prototype.flip = function() { 
    var func = this; 
    return function() { 
     var first = arguments[0]; 
     var second = arguments[1]; 
     var rest = Array.prototype.slice.call(arguments, 2); 
     var newArgs = [second, first].concat(rest); 

     return func.apply(this, newArgs); 
    }; 
}; 

/* 
e.g. 

var foo = function(a, b, c, d) { console.log(a, b, c, d); } 
var iAmA = foo.curry("I", "am", "a"); 
iAmA("Donkey"); 
-> I am a Donkey 

var bah = foo.flip(); 
bah(1, 2, 3, 4); 
-> 2 1 3 4 
*/ 
Questions connexes