web-dev-qa-db-fra.com

Appel d'une fonction dynamique avec un nombre dynamique de paramètres

Je cherche un truc à ce sujet. Je sais comment appeler une fonction dynamique et arbitraire en JavaScript, en transmettant des paramètres spécifiques, par exemple:

function mainfunc(func, par1, par2){
    window[func](par1, par2);
}

function calledfunc(par1, par2){
    // Do stuff here
}

mainfunc('calledfunc', 'hello', 'bye');

Je sais comment transmettre des paramètres facultatifs et illimités à l'aide de la collection arguments à l'intérieur de mainfunc, mais je ne vois pas comment envoyer un nombre arbitraire de paramètres à mainfunc à envoyer à calledfunc dynamiquement; comment puis-je accomplir quelque chose comme cela, mais avec un nombre quelconque d'arguments optionnels (sans utiliser ce vilain ifelse)?

function mainfunc(func){
    if(arguments.length == 3)
        window[func](arguments[1], arguments[2]);
    else if(arguments.length == 4)
        window[func](arguments[1], arguments[2], arguments[3]);
    else if(arguments.length == 5)
        window[func](arguments[1], arguments[2], arguments[3], arguments[4]);
}

function calledfunc1(par1, par2){
    // Do stuff here
}

function calledfunc2(par1, par2, par3){
    // Do stuff here
}

mainfunc('calledfunc1', 'hello', 'bye');
mainfunc('calledfunc2', 'hello', 'bye', 'goodbye');
147
ARemesal

Utilisez la méthode apply d'une fonction: -

function mainfunc (func){
    window[func].apply(null, Array.prototype.slice.call(arguments, 1));
} 

Edit: Il me semble que cela serait beaucoup plus utile avec un léger tweak: -

function mainfunc (func){
    this[func].apply(this, Array.prototype.slice.call(arguments, 1));
} 

Cela fonctionnera en dehors du navigateur (this par défaut dans l'espace global). L'utilisation de call on mainfunc fonctionnerait également: -

function target(a) {
    alert(a)
}

var o = {
    suffix: " World",
    target: function(s) { alert(s + this.suffix); }
};

mainfunc("target", "Hello");

mainfunc.call(o, "target", "Hello");
181
AnthonyWJones

Votre code ne fonctionne que pour les fonctions globales, c.-à-d. membres de l'objet window. Pour l'utiliser avec des fonctions arbitraires, transmettez la fonction elle-même à la place de son nom en tant que chaîne:

function dispatch(fn, args) {
    fn = (typeof fn == "function") ? fn : window[fn];  // Allow fn to be a function object or the name of a global function
    return fn.apply(this, args || []);  // args is optional, use an empty array by default
}

function f1() {}

function f2() {
    var f = function() {};
    dispatch(f, [1, 2, 3]);
}

dispatch(f1, ["foobar"]);
dispatch("f1", ["foobar"]);

f2();  // calls inner-function "f" in "f2"
dispatch("f", [1, 2, 3]);  // doesn't work since "f" is local in "f2"
21
Ferdinand Beyer

Vous pouvez utiliser .apply()

Vous devez spécifier un this... Je suppose que vous pouvez utiliser le this dans mainfunc.

function mainfunc (func)
{
    var args = new Array();
    for (var i = 1; i < arguments.length; i++)
        args.Push(arguments[i]);

    window[func].apply(this, args);
}
15
Greg

Voici ce dont vous avez besoin:

function mainfunc (){
    window[Array.prototype.shift.call(arguments)].apply(null, arguments);
}

Le premier argument est utilisé comme nom de la fonction et tous les autres sont utilisés comme arguments de la fonction appelée ...

Nous pouvons utiliser la méthode shift pour renvoyer puis supprimer la première valeur du tableau d'arguments. Notez que nous l'appelons depuis le prototype Array puisque, à proprement parler, 'arguments' n'est pas un tableau réel et n'hérite donc pas de la méthode shift comme le ferait un tableau normal.


Vous pouvez également appeler la méthode shift comme ceci:

[].shift.call(arguments);
12
James

Le moyen le plus simple pourrait être:

var func='myDynamicFunction_'+myHandler;
var arg1 = 100, arg2 = 'abc';

window[func].apply(null,[arg1, arg2]);

En supposant que cette fonction cible soit déjà attachée à un objet "window".

5
lubosdz

Si vous voulez passer avec "arguments" quelques autres, vous devez créer le tableau de tous les arguments ensemble, c'est-à-dire comme ceci:

var Log = {
    log: function() {
        var args = ['myarg here'];
        for(i=0; i<arguments.length; i++) args = args.concat(arguments[i]);
        console.log.apply(this, args);
    }
}
3
Pavel Křupala

Maintenant j'utilise ceci:

Dialoglar.Confirm = function (_title, _question, callback_OK) {
    var confirmArguments = arguments;
    bootbox.dialog({
        title: "<b>" + _title + "</b>",
        message: _question,
        buttons: {
            success: {
                label: "OK",
                className: "btn-success",
                callback: function () {
                    if (typeof(callback_OK) == "function") {                            callback_OK.apply(this,Array.prototype.slice.call(confirmArguments, 3));
                    }
                }
            },
            danger: {
                label: "Cancel",
                className: "btn-danger",
                callback: function () {
                    $(this).hide();
                }
            }
        }
    });
};
0
uzay95