it-swarm.com.de

So führen Sie eine JavaScript-Funktion aus, wenn ich ihren Namen als Zeichenfolge habe

Ich habe den Namen einer Funktion in JavaScript als String. Wie konvertiere ich das in einen Funktionszeiger, damit ich ihn später aufrufen kann?

Je nach den Umständen muss ich möglicherweise auch verschiedene Argumente an die Methode übergeben.

Einige der Funktionen können die Form von namespace.namespace.function(args[...]) haben.

969
Kieron

Verwenden Sie eval nur, wenn Sie absolut, positiv keine andere Wahl haben.

Wie bereits erwähnt, ist es am besten, so etwas zu verwenden:

window["functionName"](arguments);

Dies funktioniert jedoch nicht mit einer Namespace-Funktion:

window["My.Namespace.functionName"](arguments); // fail

So würden Sie das machen:

window["My"]["Namespace"]["functionName"](arguments); // succeeds

Um dies zu vereinfachen und etwas Flexibilität zu bieten, gibt es hier eine Komfortfunktion:

function executeFunctionByName(functionName, context /*, args */) {
  var args = Array.prototype.slice.call(arguments, 2);
  var namespaces = functionName.split(".");
  var func = namespaces.pop();
  for(var i = 0; i < namespaces.length; i++) {
    context = context[namespaces[i]];
  }
  return context[func].apply(context, args);
}

Sie würden es so nennen:

executeFunctionByName("My.Namespace.functionName", window, arguments);

Beachten Sie, dass Sie in jedem gewünschten Kontext übergeben können. Dies würde also das Gleiche tun wie oben:

executeFunctionByName("Namespace.functionName", My, arguments);
1353
Jason Bunting

Ich dachte nur, ich poste eine leicht veränderte Version von Jason Bunting's sehr hilfreiche Funktion .

Erstens habe ich die erste Anweisung vereinfacht, indem ich einen zweiten Parameter an slice () übergeben habe. Die ursprüngliche Version funktionierte in allen Browsern außer dem IE einwandfrei.

Zweitens habe ich dieses durch Kontext in der return-Anweisung ersetzt; Andernfalls zeigte dieses immer auf Fenster , als die Zielfunktion ausgeführt wurde hingerichtet.

function executeFunctionByName(functionName, context /*, args */) {
    var args = Array.prototype.slice.call(arguments, 2);
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for (var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }
    return context[func].apply(context, args);
}
98
Alex Nazarov

Die Antwort auf diese andere Frage zeigt Ihnen, wie das geht: Javascript entspricht Pythons locals ()?

Grundsätzlich kann man sagen

window["foo"](arg1, arg2);

oder wie viele andere vorgeschlagen haben, können Sie einfach eval verwenden:

eval(fname)(arg1, arg2);

obwohl dies äußerst unsicher ist, es sei denn, Sie sind sich absolut sicher, was Sie auswerten.

58
Eli Courtwright

Könntest du das nicht einfach machen:

var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();

Sie können mit dieser Methode auch jedes andere JavaScript ausführen.

50
Coley

Ich denke, eine elegante Art, dies zu tun, besteht darin, Ihre Funktionen in einem Hash-Objekt zu definieren. Anschließend können Sie mithilfe der Zeichenfolge einen Verweis auf diese Funktionen aus dem Hash erstellen. z.B.

var customObject = {
  customFunction: function(param){...}
};

Dann können Sie anrufen:

customObject['customFunction'](param);

Dabei ist customFunction eine Zeichenfolge, die mit einer in Ihrem Objekt definierten Funktion übereinstimmt.

42
Ruben Daddario

Mit ES6 können Sie über den Namen auf Klassenmethoden zugreifen:

class X {
  method1(){
    console.log("1");
  }
  method2(){
    this['method1']();
    console.log("2");
  }
}
let x  = new X();
x['method2']();

die Ausgabe wäre:

1
2
26
nils petersohn

Zwei Dinge:

  • vermeide eval, es ist furchtbar gefährlich und langsam

  • zweitens spielt es keine rolle, wo ihre funktion existiert, "global" -igkeit ist irrelevant. x.y.foo() kann durch x.y['foo']() oder x['y']['foo']() oder sogar window['x']['y']['foo']() aktiviert werden. Sie können unbegrenzt so verketten.

22
annakata

Bei allen Antworten wird davon ausgegangen, dass der Zugriff auf die Funktionen über den globalen Bereich (auch als Fenster bezeichnet) erfolgt. Das OP hat diese Annahme jedoch nicht getroffen.

Wenn die Funktionen in einem lokalen Bereich (auch als Closure bezeichnet) leben und nicht von einem anderen lokalen Objekt referenziert werden, ist das Pech: Sie müssen eval () verwenden. AFAIK, siehe lokale Funktion in Javascript dynamisch aufrufen

15
Wolfgang Kuehn

Sie müssen nur Ihre Zeichenfolge in einen Zeiger von window[<method name>] konvertieren. Beispiel:

var function_name = "string";
function_name = window[function_name];

und jetzt können Sie es wie einen Zeiger verwenden.

13
Amirali

Hier ist mein Beitrag zu den hervorragenden Antworten von Jason Bunting/Alex Nazarov, wo ich die von Crashalot angeforderte Fehlerprüfung einbeziehe.

Angesichts dieser (erfundenen) Präambel:

a = function( args ) {
    console.log( 'global func passed:' );
    for( var i = 0; i < arguments.length; i++ ) {
        console.log( '-> ' + arguments[ i ] );
    }
};
ns = {};
ns.a = function( args ) {
    console.log( 'namespace func passed:' );
    for( var i = 0; i < arguments.length; i++ ) {
        console.log( '-> ' + arguments[ i ] ); 
    }
};
name = 'nsa';
n_s_a = [ 'Snowden' ];
noSuchAgency = function(){};

dann die folgende Funktion:

function executeFunctionByName( functionName, context /*, args */ ) {
    var args, namespaces, func;

    if( typeof functionName === 'undefined' ) { throw 'function name not specified'; }

    if( typeof eval( functionName ) !== 'function' ) { throw functionName + ' is not a function'; }

    if( typeof context !== 'undefined' ) { 
        if( typeof context === 'object' && context instanceof Array === false ) { 
            if( typeof context[ functionName ] !== 'function' ) {
                throw context + '.' + functionName + ' is not a function';
            }
            args = Array.prototype.slice.call( arguments, 2 );

        } else {
            args = Array.prototype.slice.call( arguments, 1 );
            context = window;
        }

    } else {
        context = window;
    }

    namespaces = functionName.split( "." );
    func = namespaces.pop();

    for( var i = 0; i < namespaces.length; i++ ) {
        context = context[ namespaces[ i ] ];
    }

    return context[ func ].apply( context, args );
}

mit dieser Option können Sie eine JavaScript-Funktion nach Namen aufrufen, die in einer Zeichenfolge mit oder ohne Argumente (einschließlich Array-Objekten) gespeichert sind, und Feedback zu aufgetretenen Fehlern geben (hoffentlich abfangen).

Die Beispielausgabe zeigt, wie es funktioniert:

// calling a global function without parms
executeFunctionByName( 'a' );
  /* OUTPUT:
  global func passed:
  */

// calling a global function passing a number (with implicit window context)
executeFunctionByName( 'a', 123 );
  /* OUTPUT:
  global func passed:
  -> 123
  */

// calling a namespaced function without parms
executeFunctionByName( 'ns.a' );
  /* OUTPUT:
  namespace func passed:
  */

// calling a namespaced function passing a string literal
executeFunctionByName( 'ns.a', 'No Such Agency!' );
  /* OUTPUT:
  namespace func passed:
  -> No Such Agency!
  */

// calling a namespaced function, with explicit context as separate arg, passing a string literal and array 
executeFunctionByName( 'a', ns, 'No Such Agency!', [ 007, 'is the man' ] );
  /* OUTPUT:
  namespace func passed:
  -> No Such Agency!
  -> 7,is the man
  */

// calling a global function passing a string variable (with implicit window context)
executeFunctionByName( 'a', name );
  /* OUTPUT:
  global func passed:
  -> nsa
  */

// calling a non-existing function via string literal
executeFunctionByName( 'n_s_a' );
  /* OUTPUT:
  Uncaught n_s_a is not a function
  */

// calling a non-existing function by string variable
executeFunctionByName( n_s_a );
  /* OUTPUT:
  Uncaught Snowden is not a function
  */

// calling an existing function with the wrong namespace reference
executeFunctionByName( 'a', {} );
  /* OUTPUT:
  Uncaught [object Object].a is not a function
  */

// calling no function
executeFunctionByName();
  /* OUTPUT:
  Uncaught function name not specified
  */

// calling by empty string
executeFunctionByName( '' );
  /* OUTPUT:
  Uncaught  is not a function
  */

// calling an existing global function with a namespace reference
executeFunctionByName( 'noSuchAgency', ns );
  /* OUTPUT:
  Uncaught [object Object].noSuchAgency is not a function
  */
10
Mac

Wenn Sie mit window["functionName"] eine Funktion eines Objekts anstelle einer globalen Funktion aufrufen möchten. Du kannst es so machen;

var myObject=new Object();
myObject["functionName"](arguments);

Beispiel:

var now=new Date();
now["getFullYear"]()
9
Ahmet DAL

ACHTUNG !!!

Man sollte aus zwei Gründen versuchen, das Aufrufen einer Funktion durch einen String in JavaScript zu vermeiden:

Grund 1: Einige Code-Obfuscatoren zerstören Ihren Code, da sie die Funktionsnamen ändern und die Zeichenfolge ungültig machen.

Grund 2: Es ist viel schwieriger, Code zu verwalten, der diese Methode verwendet, da es viel schwieriger ist, die Verwendung der von einer Zeichenfolge aufgerufenen Methoden zu lokalisieren.

8
dykstrad

Hier ist mein Es6-Ansatz, mit dem Sie Ihre Funktion anhand ihres Namens als Zeichenfolge oder ihres Funktionsnamens aufrufen und außerdem verschiedene Anzahlen von Argumenten an verschiedene Funktionstypen übergeben können:

function fnCall(fn, ...args)
{
  let func = (typeof fn =="string")?window[fn]:fn;
  if (typeof func == "function") func(...args)
  else console.error(`${fn} is Not a function!`);
}


function example1(arg1){console.log(arg1)}
function example2(arg1, arg2){console.log(arg1 + "  and   " + arg2)}
function example3(){console.log("No arguments!")}

fnCall("example1", "test_1");
fnCall("example2", "test_2", "test3");
fnCall(example3);
fnCall("example4"); // should raise an error in console
6
pouyan

Abhängig davon, wo Sie sich befinden, können Sie auch Folgendes verwenden:

this["funcname"]();
self["funcname"]();
window["funcname"]();
top["funcname"]();
globalThis["funcname"]();

oder in nodejs

global["funcname"]()
6
Zibri

Überrascht, dass setTimeout nicht erwähnt wird.

So führen Sie eine Funktion ohne Argumente aus:

var functionWithoutArguments = function(){
    console.log("Executing functionWithoutArguments");
}
setTimeout("functionWithoutArguments()", 0);

So führen Sie eine Funktion mit Argumenten aus:

var functionWithArguments = function(arg1, arg2) {
    console.log("Executing functionWithArguments", arg1, arg2);
}
setTimeout("functionWithArguments(10, 20)");

So führen Sie eine Funktion mit tiefem Namensraum aus:

var _very = {
    _deeply: {
        _defined: {
            _function: function(num1, num2) {
                console.log("Execution _very _deeply _defined _function : ", num1, num2);
            }
        }
    }
}
setTimeout("_very._deeply._defined._function(40,50)", 0);
6
abhishekisnot
  let t0 = () => { alert('red0') }
  var t1 = () =>{ alert('red1') }
  var t2 = () =>{ alert('red2') }
  var t3 = () =>{ alert('red3') }
  var t4 = () =>{ alert('red4') }
  var t5 = () =>{ alert('red5') }
  var t6 = () =>{ alert('red6') }

  function getSelection(type) {
    var evalSelection = {
      'title0': t0,
      'title1': t1,
      'title2': t2,
      'title3': t3,
      'title4': t4,
      'title5': t5,
      'title6': t6,
      'default': function() {
        return 'Default';
      }
    };
    return (evalSelection[type] || evalSelection['default'])();
  }
  getSelection('title1');

Eine weitere OOP Lösung ...

3
Leo Lanese

Also, wie andere gesagt haben, ist definitiv die beste Option:

window['myfunction'](arguments)

Und wie sagte Jason Bunting funktioniert es nicht, wenn der Name Ihrer Funktion ein Objekt enthält:

window['myobject.myfunction'](arguments); // won't work
window['myobject']['myfunction'](arguments); // will work

Hier ist meine Version einer Funktion, die alle Funktionen nach Namen ausführt (einschließlich eines Objekts oder nicht):

my = {
    code : {
        is : {
            Nice : function(a, b){ alert(a + "," + b); }
        }
    }
};

guy = function(){ alert('awesome'); }

function executeFunctionByName(str, args)
{
    var arr = str.split('.');
    var fn = window[ arr[0] ];
    
    for (var i = 1; i < arr.length; i++)
    { fn = fn[ arr[i] ]; }
    fn.apply(window, args);
}

executeFunctionByName('my.code.is.Nice', ['arg1', 'arg2']);
executeFunctionByName('guy');
3
pmrotule

In meinem Code ist etwas sehr Ähnliches. Ich habe eine vom Server generierte Zeichenfolge, die einen Funktionsnamen enthält, den ich als Rückruf für eine Drittanbieter-Bibliothek übergeben muss. Ich habe also einen Code, der die Zeichenfolge übernimmt und einen "Zeiger" auf die Funktion zurückgibt, oder null, wenn er nicht gefunden wird.

Meine Lösung war " Jason Bunting's sehr hilfreiche Funktion " * sehr ähnlich, obwohl sie nicht automatisch ausgeführt wird und der Kontext immer im Fenster ist. Dies kann jedoch leicht geändert werden.

Hoffentlich hilft das jemandem weiter.

/**
 * Converts a string containing a function or object method name to a function pointer.
 * @param  string   func
 * @return function
 */
function getFuncFromString(func) {
    // if already a function, return
    if (typeof func === 'function') return func;

    // if string, try to find function or method of object (of "obj.func" format)
    if (typeof func === 'string') {
        if (!func.length) return null;
        var target = window;
        var func = func.split('.');
        while (func.length) {
            var ns = func.shift();
            if (typeof target[ns] === 'undefined') return null;
            target = target[ns];
        }
        if (typeof target === 'function') return target;
    }

    // return null if could not parse
    return null;
}
2
Nomaed

Noch ein Detail zu den Beiträgen von Jason und Alex. Ich fand es hilfreich, dem Kontext einen Standardwert hinzuzufügen. Setzen Sie einfach context = context == undefined? window:context; am Anfang der Funktion. Sie können window in den von Ihnen bevorzugten Kontext ändern und müssen dann nicht jedes Mal dieselbe Variable übergeben, wenn Sie dies in Ihrem Standardkontext aufrufen.

2
Bradley Shrader

Am einfachsten ist es, darauf zuzugreifen, als hätte es ein Element

window.ClientSideValidations.forms.location_form

ist dasselbe wie

window.ClientSideValidations.forms['location_form']
1
crazycrv

Es gibt auch einen sehr hilfreichen Weg.

http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx

var arrayMaker = {  
    someProperty: 'some value here',  
    make: function (arg1, arg2) {  
        return [ this, arg1, arg2 ];  
    },
    execute: function_name
};
1
merqlove

Um die Antwort von Jason Bunting zu ergänzen: Wenn Sie nodejs oder etwas anderes verwenden (und dies funktioniert auch in dom js), können Sie this anstelle von window verwenden (und denken Sie daran: eval is böse:

this['fun'+'ctionName']();
1
Cilan

Ich kann nicht widerstehen, einen anderen Trick zu erwähnen, der hilft, wenn Sie eine unbekannte Anzahl von Argumenten haben, die auch als Teil des Strings übergeben werden den Funktionsnamen enthält. Zum Beispiel:

var annoyingstring = 'call_my_func(123, true, "blah")';

Wenn Ihr Javascript auf einer HTML-Seite ausgeführt wird, benötigen Sie lediglich einen unsichtbaren Link. Sie können eine Zeichenfolge an das Attribut onclick übergeben und die Methode click aufrufen.

<a href="#" id="link_secret"><!-- invisible --></a>

$('#link_secret').attr('onclick', annoyingstring);
$('#link_secret').click();

Oder erstellen Sie das <a> -Element zur Laufzeit.

1
Magnus Smith

Grundlegend aussehen:

var namefunction = 'jspure'; // String

function jspure(msg1 = '', msg2 = '') { 
  console.log(msg1+(msg2!=''?'/'+msg2:''));
} // multiple argument

// Results ur test
window[namefunction]('hello','hello again'); // something...
eval[namefunction] = 'hello'; // use string or something, but its eval just one argument and not exist multiple

Existieren andere Art Funktion ist Klasse und schauen Sie Beispiel nils petersohn

0
KingRider

alles, was Sie tun müssen, ist, einen Kontext zu verwenden oder einen neuen Kontext zu definieren, in dem sich Ihre Funktion (en) befinden. Sie sind nicht auf window["f"](); beschränkt

hier ist ein Beispiel, wie ich einen dynamischen Aufruf für einige REST -Dienste verwende.

/* 
Author: Hugo Reyes
@ www.teamsrunner.com

*/

    (function ( W, D) { // enclose it as self invoking function to avoid name collisions.


    // to call function1 as string
    // initialize your FunctionHUB as your namespace - context
    // you can use W["functionX"](), if you want to call a function at the window scope.
    var container = new FunctionHUB();


    // call a function1 by name with one parameter.

    container["function1"](' Hugo ');


    // call a function2 by name.
    container["function2"](' Hugo Leon');


    // OO style class
    function FunctionHUB() {

        this.function1 = function (name) {

            console.log('Hi ' + name + ' inside function 1')
        }

        this.function2 = function (name) {

            console.log('Hi' + name + ' inside function 2 ')
        }
    }

})(window, document); // in case you need window context inside your namespace.

Wenn Sie die gesamte Funktion aus einer Zeichenfolge generieren möchten, ist das eine andere Antwort. Beachten Sie auch, dass Sie nicht auf einen einzelnen Namensraum beschränkt sind. Wenn Ihr Namensraum als my.name.space.for.functions.etc.etc.etc existiert, enthält der letzte Zweig Ihres Namensraums die Funktion als my.name.space.for.functions.etc.etc["function"]();.

Ich hoffe es hilft. H.

0
Hugo R

Danke für die sehr hilfreiche Antwort. Ich benutze Jason Bunting's Funktion in meinen Projekten.

Ich habe es erweitert, um es mit einer optionalen Zeitüberschreitung zu verwenden, da die normale Methode zum Festlegen einer Zeitüberschreitung nicht funktioniert. Siehe abhishekisnots Frage

function executeFunctionByName(functionName, context, timeout /*, args */ ) {
        var args = Array.prototype.slice.call(arguments, 3);
        var namespaces = functionName.split(".");
        var func = namespaces.pop();
        for (var i = 0; i < namespaces.length; i++) {
                context = context[namespaces[i]];
        }
        var timeoutID = setTimeout(
                function(){ context[func].apply(context, args)},
                timeout
        );
    return timeoutID;
}

var _very = {
    _deeply: {
        _defined: {
            _function: function(num1, num2) {
                console.log("Execution _very _deeply _defined _function : ", num1, num2);
            }
        }
    }
}

console.log('now wait')
executeFunctionByName("_very._deeply._defined._function", window, 2000, 40, 50 );
0
Neo

Da eval() böse ist und new Function() nicht der effizienteste Weg ist, dies zu erreichen, ist hier eine schnelle JS-Funktion, die die Funktion von ihrem Namen in einer Zeichenfolge zurückgibt.

  • Funktioniert für Namespace-Funktionen
  • Fallbacks auf Null-Funktion im Fall von Null/undefiniertem String
  • Fallbacks auf Null-Funktion, wenn Funktion nicht gefunden wird
 
 Funktion convertStringtoFunction (functionName) {
 
 var nullFunc = function () {}; // Fallback Null-Funktion 
 Var ret = window; // Top Level Namespace 
 
 // Wenn null/undefinierter String, dann gebe eine Null-Funktion zurück 
 If (functionName == null) return nullFunc; 
 
 // String in Funktionsnamen 
 Umwandeln functionName.split ('.'). ForEach (Funktion (Taste) {ret = ret [Taste];}); 
 
 // Wenn der Funktionsname nicht verfügbar ist, dann gebe eine Null-Funktion zurück, ansonsten die eigentliche Funktion 
 Return (ret == null? NullFunc: ret); 
 
} 
 

Verwendung:

 
 convertStringtoFunction ("level1.midLevel.myFunction") (arg1, arg2, ...); 
 
0
SJ00

Es gibt verschiedene executeByName Funktionen, die gut funktionieren, es sei denn, der Name enthält eckige Klammern - Probleme, auf die ich gestoßen bin - da ich dynamisch generierte Namen habe. Die obigen Funktionen schlagen also bei Namen wie fehl

app.widget['872LfCHc']['toggleFolders']

Als Abhilfe habe ich die Funktion gemacht, dies auch zu berücksichtigen, vielleicht findet es jemand nützlich:

Aus CoffeeScript generiert:

var executeByName = function(name, context) {
  var args, func, i, j, k, len, len1, n, normalizedName, ns;
  if (context == null) {
    context = window;
  }
  args = Array.prototype.slice.call(arguments, 2);
  normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.');
  ns = normalizedName.split(".");
  func = context;
  for (i = j = 0, len = ns.length; j < len; i = ++j) {
    n = ns[i];
    func = func[n];
  }
  ns.pop();
  for (i = k = 0, len1 = ns.length; k < len1; i = ++k) {
    n = ns[i];
    context = context[n];
  }
  if (typeof func !== 'function') {
    throw new TypeError('Cannot execute function ' + name);
  }
  return func.apply(context, args);
}

Zur besseren Lesbarkeit auch die CoffeeScript-Version prüfen:

executeByName = (name, context = window) ->
    args = Array.prototype.slice.call(arguments, 2)
    normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.')
    ns = normalizedName.split "."
    func = context
    for n, i in ns
        func = func[n]

    ns.pop()
    for n, i in ns
        context = context[n];
    if typeof func != 'function'
        throw new TypeError 'Cannot execute function ' + name
    func.apply(context, args)
0
PeterM

Sie können die Javascript-Funktion auch innerhalb von eval("functionname as string") aufrufen. Wie unten: (eval ist reine Javascript-Funktion)

function testfunc(){
    return "hello world";
}

$( document ).ready(function() {

     $("div").html(eval("testfunc"));
});

Arbeitsbeispiel: https://jsfiddle.net/suatatan/24ms0fna/4/

0
Suat Atan PhD
use this

function executeFunctionByName(functionName, context /*, args */) {
      var args = [].slice.call(arguments).splice(2);
      var namespaces = functionName.split(".");
      var func = namespaces.pop();
      for(var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
      }
      return context[func].apply(context, args);
    }
0
Pratik

Das funktioniert bei mir:

var command = "Add";
var tempFunction = new Function("Arg1","Arg2", "window." + command + "(Arg1,Arg2)");
tempFunction(x,y);

Ich hoffe das funktioniert.

0
DevAshish

Ohne Verwendung von eval('function()') können Sie mit new Function(strName) eine neue Funktion erstellen. Der folgende Code wurde mit FF, Chrome, IE getestet.

<html>
<body>
<button onclick="test()">Try it</button>
</body>
</html>
<script type="text/javascript">

  function test() {
    try {    
        var fnName = "myFunction()";
        var fn = new Function(fnName);
        fn();
      } catch (err) {
        console.log("error:"+err.message);
      }
  }

  function myFunction() {
    console.log('Executing myFunction()');
  }

</script>
0
Ithar