2009-04-21 18 views
36

En JavaScript, si tengo una cadena en una variable, ¿hay alguna manera de obtener una referencia al objeto de función que tiene ese nombre coincidente? Tenga en cuenta que jQuery está disponible para mí, así que también puedo usar cualquiera de sus métodos de ayuda.¿Obtiene el objeto de función JavaScript a partir de su nombre como una cadena?

Por ejemplo:

myFunction = function(){}; 

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

Gracias

Respuesta

58

si se sabe que es una función global que puede utilizar:

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

reemplazar lo contrario ventana con el objeto principal que contiene la función .

+5

para pasar argumentos: ventana [FUNC_NAME] (myArg1, myArg2); – mpemburn

9

este [nombre_func] debería darle la función.

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

Acabo de probar eso en Firebug y no funcionó. Tal vez se comporta de manera diferente en una página web? – rmeador

+0

Depende de dónde esté definida su función. Si la función no está definida en 'esto', entonces no la encontrará. Es posible que deba probar la ventana [nombre_func] o Some.Other.Object [nombre_func] –

4

Uso eval:

myFunction = function(){}; 

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

eval es malo. no use eval – mkoryak

+3

¿por qué? ¿Puedes citar algunas buenas razones? –

+0

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

21

acabo de hacer una prueba rápida en Firebug y yo era capaz de conseguir la función del nombre simplemente eval() ing el nombre ... me siento sucia usando eval() , pero parece hacer el trabajo aquí bastante bien.

var myFunctionPtr = eval(func_name); 
+0

¿Puede pasar parámetros de esa manera? –

+0

Ciertamente, una vez que tiene myFunctionPtr, lo usa como una función normal. –

+0

o puede usar la ventana [func_name] que también hace el trabajo. – mkoryak

3

Una manera segura de hacer es sandbox la supuesta función mientras se prueba su tipo:

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! 

La salida:

  • "realFunction" es una función
  • "notHere" no es una función
  • "alert ('malicioso')" no es una función
  • "error de sintaxis {" no es una función

El código de caja de arena se puede escribir de una manera más concisa pero me gusta utilizando funciones de "plantilla" en lugar de incrustar código JS como literales de cadena.

Y oh, esto lo hace muy bien sin usar eval - aunque se puede argumentar que usar un constructor de Función no es diferente de eval.

14

Nunca es un enfoque preferido. En lugar de mantener el nombre de la función en func_name, podría haber mantenido la referencia a una función con el mismo éxito en algo como func_to_call.

Si es absolutamente necesita para mantener una referencia de función como una cadena, normalmente se utilizaría una tabla hash para asignar un nombre arbitrario a una variable (JS cuenta con primera clase de funciones que permite)

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

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

Fiddled (no sé por qué, es un guión tan pequeña :)

se sugirió que utilice eval(func_name) - sin embargo, esto podría obtener rápidamente fuera de control debido a JS alcance.

También ha declarado su myFunction = function(){}; como una variable global. Por un lado, le permite referenciarlo como window[func_name] pero, por otro lado, contamina el alcance global.

+1

+1 Esta solución funciona y, sorprendentemente, nunca se votó al alza. Lo encontré el más elegante para mi caso de uso. – bernardn

+0

incluso mejor para cosas simples, solo podría pasar un delegado alrededor de –

+0

Iniciando un control desde MVC Razor, por lo que el nombre de la función de devolución de llamada debe aparecer como una cadena C#. Por lo tanto, eval es la elección más simple. – Triynko

0

conocer la función y luego los

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

llaman Depende de donde y cómo la función es (o no es) declararon.

Si se trata de un mundial y no declarado a través de let name = ... o const name = ... sintaxis (y que no es un constructor de la clase declarada con class), se puede comprobar mediante la búsqueda de ella como una propiedad del objeto global. (Esas advertencias son todas cosas ES2015, más abajo.) Puede obtener una referencia al objeto global a través del this en modo suelto en ámbito global; los navegadores también te dan un número global llamado window. Así que asumiendo un navegador:

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

Si pudiera no ser global, sino más bien es sólo en su alcance debido a que su código se cierra sobre ella, o si se ha creado usando uno de esos mecanismos ES2015 he mencionado, hay realmente no hay buena manera de comprobar que no sea eval:

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

Usando eval es un último recurso, y hay que única utilizarlo con entrada controlada estrictamente. Pero cuando tienes que hacerlo, y tienes una entrada estrictamente controlada, está bien.


Acerca de las advertencias ES2015:

El nuevo let, const y class son bestias muy interesantes: Cuando se utiliza en el ámbito global, crean globales, pero No crear propiedades en el objeto global. A partir de ES2015, aunque todas las propiedades del objeto global son globales, no todas las propiedades globales del objeto global. Todo es parte de tratar de controlar el espacio de nombres global ampliamente contaminado y también aportar una mayor seguridad al modelo de enlace de JavaScript. (Ahora que tenemos módulos verdaderos.)

Así que (tenga en cuenta que esto sólo funcionará en los navegadores de última generación):

// 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; 
 
}

de salida en los navegadores de última generación:

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

Nota: Algunos los transpilers no hacen cumplir esto rigurosamente, así que si ves diferentes resultados en el código transpilado, no te sorprendas.

0

Para nodejs

Escriba sus funciones en un archivo separado y exportarlos y utilizar con referencia nombre del que llamarlos, igual que

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

Uso función definida en functions.js en index.js:

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

SALIDA:

> node index.js 
> function ONE called 
Cuestiones relacionadas