2009-04-21 19 views
36

In JavaScript, wenn ich eine Zeichenfolge in einer Variablen habe, gibt es eine Möglichkeit, einen Verweis auf das Funktionsobjekt, das diesen passenden Namen hat, zu erhalten? Beachten Sie, dass jQuery für mich verfügbar ist, sodass ich auch eine beliebige seiner Hilfsmethoden verwenden kann.Erhalten JavaScript-Funktion-Objekt von seinem Namen als Zeichenfolge?

Zum Beispiel:

myFunction = function(){}; 

var func_name = "myFunction"; 
var myFunctionPtr = ??? //how to get the function from the name 

Dank

Antwort

58

, wenn Sie wissen, dass es eine globale Funktion, die Sie verwenden können:

var functPtr = window[func_name]; 
//functPtr() 

die Funktion mit dem übergeordneten Objekt Fenster enthält, andernfalls ersetzen .

+5

Argumente zu übergeben: window [func_name] (myArg1, myArg2); – mpemburn

9

dies [func_name] sollte Ihnen die Funktion geben.

var myfunc = this[func_name]; 
myfunc(); 
+0

Ich habe das gerade in Firebug versucht und es hat nicht funktioniert. Vielleicht verhält es sich auf einer Webseite anders? – rmeador

+0

Es hängt davon ab, wo Ihre Funktion definiert ist. Wenn die Funktion nicht auf 'this' definiert ist, wird sie nicht gefunden. Möglicherweise müssen Sie versuchen, Fenster [func_name] oder Some.Other.Object [func_name] –

4

Verwendung eval:

myFunction = function(){}; 

var func_name = "myFunction"; 
var myFunctionPtr = eval(func_name); 
+2

Eval ist böse. Verwenden Sie nicht eval – mkoryak

+3

warum? können Sie einige gute Gründe nennen. –

+0

http://stackoverflow.com/questions/86513/why-is-using-javascript-eval-function-a-bad-idea – Miles

21

Ich habe gerade einen schnellen Test in Firebug und ich konnte durch die Funktion aus dem Namen erhalten einfach eval() den Namen ing ... ich schmutzig fühlen mit eval() , aber es scheint die Arbeit hier ziemlich gut zu erledigen.

var myFunctionPtr = eval(func_name); 
+0

Können Sie Parameter auf diese Weise übergeben? –

+0

Sicher - sobald Sie myFunctionPtr haben, verwenden Sie es als eine normale Funktion. –

+0

oder Sie können das Fenster [func_name] verwenden, das den Job erledigt. – mkoryak

3

Eine sichere Art und Weise zu tun, um die angebliche Funktion Sandbox während seiner Art Prüfung:

function isFunction(expr) { 
    function sandboxTemplate() { 
     var window, document, alert; // etc. 

     try { 
      return typeof $expr$ == "function"; 
     } catch (e) { 
      return false; 
     } 
    } 

    try { 
     var sandbox = new Function(
      sandboxTemplate.toString().replace("$expr$", expr) 
      + "return sandboxTemplate()"); 
     return sandbox(); 
    } catch (e) { 
     return false; 
    } 
} 

function test(expr) { 
    document.write("<div>\"" + expr + "\" <b>is " 
     + (isFunction(expr) ? "" : "not ") 
     + "</b>a function</div>"); 
} 

/* Let's do some testing */ 

function realFunction() { 
} 

test("realFunction");  // exists! 
test("notHere");   // non-existent 
test("alert('Malicious')"); // attempt to execute malicious code! 
test("syntax error {");  // attempt to blow us up! 

Der Ausgang:

  • "realFunction" ist eine Funktion
  • "notHere" ist nicht eine Funktion
  • „alert (‚Malicious‘)“ ist nicht eine Funktion
  • „Syntaxfehler {“ ist nicht eine Funktion

Der Sandbox-Code in einer prägnanten Weise geschrieben werden könnte, aber Ich mag Verwenden von "Template" -Funktionen anstatt JS-Code als String-Literale einzubetten.

Und oh, das macht es schön ohne eval zu verwenden - obwohl man argumentieren kann, dass die Verwendung eines Funktionskonstruktors nicht anders ist als ein eval.

14

Dies ist nie ein bevorzugter Ansatz. Anstatt den Funktionsnamen in func_name zu behalten, hätten Sie den Verweis auf eine Funktion genauso erfolgreich in etwas wie func_to_call behalten können.

Wenn Sie unbedingt benötigen die Funktionsreferenz als eine Zeichenfolge zu halten, würden Sie in der Regel eine Hash-Tabelle verwenden Sie einen beliebigen Namen einer Variablen zur Karte (JS verfügt über erstklassige Funktionen, die es ermöglicht)

myFunction = function(){}; 
var obj = {func_name: myFunction}; 

obj['func_name']();//executes the function 

Fiddled (ich weiß nicht, warum es ein solches kleines Skript ist :)

es wurde vorgeschlagen, dass Sie eval(func_name) verwenden - aber dies schnell wegen JS Scoping außer Kontrolle geraten könnte.

Sie haben auch Ihre myFunction = function(){}; als globale Variable deklariert. Auf der einen Seite lässt es Sie als window[func_name] verweisen, auf der anderen Seite aber verschmutzt es den globalen Geltungsbereich.

+1

+1 Diese Lösung funktioniert und wurde überraschenderweise nie aktualisiert. Ich fand es das eleganteste für meinen Anwendungsfall. – bernardn

+0

noch besser für einfache Sachen, die Sie einfach einen Delegaten um –

+0

übergeben können Instantiieren eines Steuerelements von MVC Razor, so dass der Name der Callback-Funktion als C# -String kommen muss. Daher ist eval die einfachste Wahl. – Triynko

0

die Funktion gefunden und nennen sie dann

autoCallBack : function(_action){ 
      $(".module").each(function(){ 
       var modulName = $(this).attr("id"); 
       if(isFunction(modulName)){ 
        eval(modulName)(); 
       } 
      }); 
     } 

isFunction : function(_functionName){ 
     try { 
      eval(_functionName); 
     } catch (error) { 
      return false; 
     } 
    return true; 
} 
5

Es hängt davon ab, wo und wie die Funktion ist (oder nicht) erklärt.

Wenn es ein globale und nicht über let name = ... oder const name = ... Syntax erklärt (und es ist nicht eine Klasse Konstruktor mit class deklarierte), können Sie mit der Suche nach ihm als Eigenschaft auf dem globalen Objekt überprüfen können. (Diese Vorbehalte sind alles ES2015-Dinge, mehr unten.) Sie können einen Verweis auf das globale Objekt über this im loose-Modus auf globaler Ebene erhalten; Browser geben Ihnen auch einen globalen Namen window. So unter der Annahme eines Browser:

if (typeof window[func_name] === "function") { 
    // .... 
} 

Wenn es könnte nicht ein global sein, sondern nur in ihrem Umfang, weil Ihr Code über sie schließt, oder wenn es erstellt wurde, eine jener ES2015 Mechanismen bereits erwähnt, gibt es wirklich keine gute Möglichkeit, andere zu prüfen als eval:

if (eval("typeof " + func_name) === "function") { 
    // .... 
} 

mit eval ein letzter Ausweg ist, und Sie müssen es nur mit streng gesteuerten Eingang verwenden. Aber wenn Sie müssen und Sie streng kontrollierten Input haben, ist es in Ordnung.


Über die ES2015 Einsprüche:

Die neue let, const und class sind sehr interessant beasties: Wenn Sie im globalen Bereich verwendet wird, schaffen sie Globals, aber sie nicht erstellen Eigenschaften auf das tun globales Objekt. Ab ES2015 sind nicht alle globalen Variablen Eigenschaften des globalen Objekts, obwohl alle Eigenschaften des globalen Objekts globale Variablen sind. Es ist Teil des Versuchs, den stark verschmutzten globalen Namespace zu zügeln und dem JavaScript-Bindungsmodell mehr Sicherheit zu geben. (Jetzt haben wir echte Module.

)

So (beachten Sie, dass dies nur in modernste Browser ausgeführt wird):

// Global scope, in a browser (because I used `window` and `document.body`) that 
 
// implements this aspect of ES2015 (as I write this, Firefox's SpiderMonkey 
 
// doesn't, Chrome's V8 does on the latest Chrome; expect SpiderMonkey and IE 
 
// to catch up pretty quick (didn't test IE Edge, maybe it's already there) 
 

 
// Strict mode isn't required for this behavior, but for the moment V8 only 
 
// supports the block-scoped constructs in strict mode. 
 
"use strict"; 
 
let tbody = setup(); 
 

 
// Old-fashioned var: Creates a property on the global object, so 
 
// we get "function, function" 
 
var f1 = function() { /*...*/ }; 
 
result("var declaration", typeof f1, typeof window["f1"]); 
 

 
// Function declaration: Creates a property on the global object, so 
 
// "function, function" 
 
function f2() {} 
 
result("function declaration", typeof f2, typeof window["f2"]); 
 

 
// `let` declaration: Doesn't create property on global object, so 
 
// "function, undefined" 
 
let f3 = function() { /*...*/ }; 
 
result("let declaration", typeof f3, typeof window["f3"]); 
 

 
// `const` declaration: Doesn't create property on global object, so 
 
// "function, undefined" 
 
const f4 = function() { /*...*/ }; 
 
result("const declaration", typeof f4, typeof window["f4"]); 
 

 
// `class` declaration: Doesn't create property on global object, so 
 
// "function, undefined" 
 
class C1 {} 
 
result("class declaration", typeof C1, typeof window["C1"]); 
 

 
function setup() { 
 
    document.body.insertAdjacentHTML(
 
    "beforeend", 
 
    "<table>" + 
 
    "<thead>" + 
 
    "<tr><th>test</th><th>global</th><th>prop</th></tr>" + 
 
    "</thead>" + 
 
    "<tbody></tbody>" + 
 
    "</table>" 
 
); 
 
    return document.body.querySelector("tbody"); 
 
} 
 

 
function result(label, direct, win) { 
 
    tbody.insertAdjacentHTML(
 
    "beforeend", 
 
    "<tr><td>" + [label, direct, win].join("</td><td>") + "</td></tr>" 
 
); 
 
}
body { 
 
    font-family: sans-serif; 
 
} 
 
table { 
 
    border-collapse: collapse; 
 
} 
 
th, td { 
 
    border: 1px solid #ddd; 
 
    padding: 4px 8px; 
 
}

Ausgabe auf topaktuelle Browser:

 
+----------------------+------------+-----------+ 
|   test   | global | prop | 
+----------------------+------------+-----------+ 
| var declaration  | function | function | 
| function declaration | function | function | 
| let declaration  | function | undefined | 
| const declaration | function | undefined | 
| class declaration | function | undefined | 
+----------------------+------------+-----------+ 

Hinweis: Einige transpilers erzwingen dies nicht streng. Wenn Sie also unterschiedliche Ergebnisse in transpiliertem Code sehen, seien Sie nicht überrascht.

0

Für NodeJS

Ihre Funktionen in einer separaten Datei schreiben und sie exportieren und mit dem Namen Verweis davon verwenden sie zu nennen, wie

// functions.js 
var funcOne = function(){ 
        console.log('function ONE called') 
       } 
module.exports={ 
    // name_exported : internal_name 
    funcOne : funcOne 
} 

Verwenden Sie die Funktion in functions.js definiert in index.js:

// index.js 
var methods = require('./functions.js') // path to functions.js 
methods['funcOne']() 

OUTPUT:

> node index.js 
> function ONE called 
Verwandte Themen