Existe-t-il un moyen de créer une fonction à partir d'une chaîne avec javascript?

107

Par exemple;

var s = "function test(){
  alert(1);
}";

var fnc = aMethod(s);

Si c'est la chaîne, je veux une fonction qui s'appelle fnc. Et fnc();apparaît un écran d'alerte.

eval("alert(1);") ne résout pas mon problème.

ymutlu
la source

Réponses:

73

J'ai ajouté un test jsperf pour 4 façons différentes de créer une fonction à partir d'une chaîne:

  • Utilisation de RegExp avec la classe Function

    var func = "function (a, b) { return a + b; }".parseFunction();

  • Utilisation de la classe Function avec "return"

    var func = new Function("return " + "function (a, b) { return a + b; }")();

  • Utilisation du constructeur de fonctions officiel

    var func = new Function("a", "b", "return a + b;");

  • Utiliser Eval

    eval("var func = function (a, b) { return a + b; };");

http://jsben.ch/D2xTG

2 échantillons de résultats: entrez la description de l'image ici entrez la description de l'image ici

phnah
la source
@KthProg Chill down;). Ce n'est pas toujours mauvais, comme dans cette situation, le jsperf est en panne pour le moment, heureusement j'ai ajouté les captures d'écran du résultat avant qu'il ne soit en panne, quand j'ai reçu le commentaire de Bulk.
phnah
@KthProg Pour info, c'était une réponse prédéfinie générée par le système de modération :) elle apparaît dans une file d'attente et nous vérifions les problèmes prédéterminés, dont l'un est conçu pour résoudre ce commentaire. Ce n'est pas une règle absolue et vous remarquerez que le commentaire est sous la forme d'une suggestion et non d'une commande.
Dan Smith
174

Une meilleure façon de créer une fonction à partir d'une chaîne est d'utiliser Function:

var fn = Function("alert('hello there')");
fn();

Cela a pour avantage / désavantage que les variables de la portée actuelle (si ce n'est globale) ne s'appliquent pas à la fonction nouvellement construite.

Passer des arguments est également possible:

var addition = Function("a", "b", "return a + b;");
alert(addition(5, 3)); // shows '8'
Lekensteyn
la source
5
D'accord, avec Functionvous ne polluez pas la portée locale et c'est pourquoi cela evalrend l'optimisation si difficile pour les moteurs ... Avec l'exemple OP, je voudrais:var fnc = Function('return '+s)();
CMS
Je pense que cela devrait probablement être la réponse acceptée. C'est beaucoup plus sûr que eval ().
Bryan Rayner
Vous, mon ami, méritez beaucoup de votes positifs. Cela présente l'avantage de créer un objet fonction qui peut être affecté à des événements, etc. Par exemple: element.onclick = Function ("alert ('test');");
Ryan Griggs
1
@RyanGriggs Dans votre cas, vous n'avez pas besoin de la fonctionnalité "eval", il est donc préférable de l'écrire sous la forme element.onclick = function() { alert("test"); }.
Lekensteyn
1
Vous avez raison de mon exemple. Cependant, si vous vouliez attribuer des fonctions arbitraires stockées dans des chaînes, votre méthode est parfaite. C'est ce que j'essaye de faire. J'ai plusieurs fonctions stockées dans des variables de chaîne et je souhaite en attribuer une à une action onclick.
Ryan Griggs
38

Vous êtes assez proche.

//Create string representation of function
var s = "function test(){  alert(1); }";

//"Register" the function
eval(s);

//Call the function
test();

Voici un violon qui fonctionne .

James Hill
la source
Je savais que la fonction était déclarée, mais je ne pouvais pas deviner appeler le nom de la fonction. Merci beaucoup.
ymutlu
4
evalAvertissement obligatoire aux futurs chercheurs: evalpeut ouvrir des failles pour les pirates: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... mais si vous connaissez ses dangers et pouvez les éviter, alors c'est un bon moyen simple de créer une fonction à partir d'une chaîne
que faire si vous n'avez pas le nom de la fonction puisqu'elle provient d'un enregistrement de base de données?
Marcel Djaman
13

Oui, l'utilisation Functionest une excellente solution mais nous pouvons aller un peu plus loin et préparer un analyseur universel qui analyse la chaîne et la convertit en véritable fonction JavaScript ...

if (typeof String.prototype.parseFunction != 'function') {
    String.prototype.parseFunction = function () {
        var funcReg = /function *\(([^()]*)\)[ \n\t]*{(.*)}/gmi;
        var match = funcReg.exec(this.replace(/\n/g, ' '));

        if(match) {
            return new Function(match[1].split(','), match[2]);
        }

        return null;
    };
}

exemples d'utilisation:

var func = 'function (a, b) { return a + b; }'.parseFunction();
alert(func(3,4));

func = 'function (a, b) { alert("Hello from function initiated from string!"); }'.parseFunction();
func();

voici jsfiddle

M. Citrouille
la source
salut s'il vous plaît prendre en charge la fonction de flèche pour cette méthode?
sathish kumar
1
Je reçois cette erreur dans typescirpt "La propriété 'parseFunction' n'existe pas sur le type 'String'."
Cegone
11

Noms de fonction dynamiques dans JavaScript

En utilisant Function

var name = "foo";
// Implement it
var func = new Function("return function " + name + "(){ alert('hi there!'); };")();
// Test it
func();
// Next is TRUE
func.name === 'foo'

Source: http://marcosc.com/2012/03/dynamic-function-names-in-javascript/

En utilisant eval

var name = "foo";
// Implement it
eval("function " + name + "() { alert('Foo'); };");
// Test it
foo();
// Next is TRUE
foo.name === 'foo'

En utilisant sjsClass

https://github.com/reduardo7/sjsClass

Exemple

Class.extend('newClassName', {
    __constructor: function() {
        // ...
    }
});

var x = new newClassName();
// Next is TRUE
newClassName.name === 'newClassName'
Eduardo Cuomo
la source
6

Cette technique peut être finalement équivalente à la méthode eval, mais je voulais l'ajouter, car elle pourrait être utile pour certains.

var newCode = document.createElement("script");

newCode.text = "function newFun( a, b ) { return a + b; }";

document.body.appendChild( newCode );

C'est fonctionnellement comme ajouter cet élément <script> à la fin de votre document, par exemple:

...

<script type="text/javascript">
function newFun( a, b ) { return a + b; }
</script>

</body>
</html>
David Newberry
la source
3

Utilisez le new Function()avec un retour à l'intérieur et exécutez-le immédiatement.

var s = `function test(){
  alert(1);
}`;

var new_fn = new Function("return " + s)()
console.log(new_fn)
new_fn()

Fernando Carvajal
la source
1

Un exemple avec des arguments dynamiques:

let args = {a:1, b:2}
  , fnString = 'return a + b;';

let fn = Function.apply(Function, Object.keys(args).concat(fnString));

let result = fn.apply(fn, Object.keys(args).map(key=>args[key]))
brunettdan
la source
Merci. Très intéressant
Дмитрий Васильев