tipos - tablas dinamicas html javascript
Cómo ejecutar una función de JavaScript cuando tengo su nombre como una cadena (30)
¿No podrías simplemente hacer esto?
var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();
También puede ejecutar cualquier otro JavaScript utilizando este método.
Tengo el nombre de una función en JavaScript como una cadena. ¿Cómo puedo convertir eso en un puntero de función para poder llamarlo más tarde?
Dependiendo de las circunstancias, es posible que tenga que pasar varios argumentos en el método también.
Algunas de las funciones pueden tomar la forma de namespace.namespace.function(args[...])
.
Aquí está mi contribución a las excelentes respuestas de Jason Bunting / Alex Nazarov, donde incluyo la verificación de errores solicitada por Crashalot.
Dado este preámbulo (artificial):
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(){};
entonces la siguiente función:
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 );
}
le permitirá llamar a una función javascript por su nombre almacenado en una cadena, ya sea espacio de nombre o global, con o sin argumentos (incluidos los objetos de Array), proporcionando comentarios sobre cualquier error encontrado (con suerte, detectándolos).
La salida de muestra muestra cómo funciona:
// 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
*/
Aquí está mi enfoque de Es6 que le permite llamar a su función por su nombre como cadena o su nombre de función y también le permite pasar diferentes números de argumentos a diferentes tipos de funciones:
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
Aquí hay varias funciones executeByName
que funcionan bien, a menos que el nombre contenga corchetes (problema con el que me encontré), ya que tengo nombres generados dinámicamente. Así que las funciones anteriores fallarán en nombres como
app.widget[''872LfCHc''][''toggleFolders'']
Como remedio, he hecho una función para tener esto en cuenta también, tal vez alguien lo encuentre útil:
Generado a partir de CoffeeScript:
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);
}
Para una mejor legibilidad, verifique también la versión de CoffeeScript:
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)
Con ES6 puedes acceder a los métodos de clase por nombre:
class X {
method1(){
console.log("1");
}
method2(){
this[''method1'']();
console.log("2");
}
}
let x = new X();
x[''method2'']();
La salida sería:
1
2
Creo que una forma elegante de hacerlo es definiendo sus funciones en un objeto hash. Luego puede tener una referencia a esas funciones desde el hash usando la cadena. p.ej
var customObject = {
customFunction: function(param){...}
};
Entonces puedes llamar:
customObject[''customFunction''](param);
Donde customFunction será una cadena que coincida con una función definida en su objeto.
Dos cosas:
Evita eval, es terriblemente peligroso y lento.
en segundo lugar, no importa dónde exista su función, la condición "global" es irrelevante.
xyfoo()
se puede habilitar mediantexy[''foo'']()
ox[''y''][''foo'']()
o incluso en lawindow[''x''][''y''][''foo'']()
. Puedes encadenar indefinidamente así.
Entonces, como han dicho otros, definitivamente la mejor opción es:
window[''myfunction''](arguments)
Y como dijo Jason Bunting , no funcionará si el nombre de su función incluye un objeto:
window[''myobject.myfunction''](arguments); // won''t work
window[''myobject''][''myfunction''](arguments); // will work
Así que aquí está mi versión de una función que ejecutará todas las funciones por nombre (incluido un objeto o no):
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'');
Esto es trabajo para mí:
var command = "Add";
var tempFunction = new Function("Arg1","Arg2", "window." + command + "(Arg1,Arg2)");
tempFunction(x,y);
Espero que esto funcione.
Gracias por la respuesta muy útil. Estoy usando la función de Jason Bunting en mis proyectos.
Lo extendí para usarlo con un tiempo de espera opcional, porque la forma normal de establecer un tiempo de espera no funciona. Ver la pregunta de abhishekisnot.
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 );
Hay algo muy similar en mi código. Tengo una cadena generada por el servidor que contiene un nombre de función que debo pasar como devolución de llamada para una biblioteca de terceros. Así que tengo un código que toma la cadena y devuelve un "puntero" a la función, o nulo si no se encuentra.
Mi solución fue muy similar a la " función muy útil de Jason Bunting " * , aunque no se ejecuta automáticamente, y el contexto está siempre en la ventana. Pero esto puede ser fácilmente modificado.
Esperemos que esto sea de ayuda para alguien.
/**
* 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;
}
La forma más fácil es acceder a ella como tiene elemento.
window.ClientSideValidations.forms.location_form
es igual que
window.ClientSideValidations.forms[''location_form'']
La respuesta a esta otra pregunta le muestra cómo hacerlo: ¿el equivalente en Javascript de los locales de Python ()?
Básicamente se puede decir
window["foo"](arg1, arg2);
o como muchos otros han sugerido, puedes usar eval:
eval(fname)(arg1, arg2);
aunque esto es extremadamente peligroso a menos que esté absolutamente seguro de lo que está evaluando.
Look básico:
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
Existe otro tipo de función es clase y mira ejemplo nils petersohn
No puedo resistirme a mencionar otro truco, lo que ayuda si tiene un número desconocido de argumentos que también se pasan como parte de la cadena que contiene el nombre de la función. Por ejemplo:
var annoyingstring = ''call_my_func(123, true, "blah")'';
Si su Javascript se está ejecutando en una página HTML, todo lo que necesita es un enlace invisible; puede pasar una cadena al atributo onclick
y luego llamar al método de click
.
<a href="#" id="link_secret"><!-- invisible --></a>
$(''#link_secret'').attr(''onclick'', annoyingstring);
$(''#link_secret'').click();
O crea el elemento <a>
en tiempo de ejecución.
No use eval
menos que absolutamente, positivamente no tenga otra opción.
Como se ha mencionado, usar algo como esto sería la mejor manera de hacerlo:
window["functionName"](arguments);
Eso, sin embargo, no funcionará con una función de espacio de nombres:
window["My.Namespace.functionName"](arguments); // fail
Así es como harías eso:
window["My"]["Namespace"]["functionName"](arguments); // succeeds
Para facilitarlo y proporcionar cierta flexibilidad, aquí hay una función de conveniencia:
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);
}
Usted lo llamaría así:
executeFunctionByName("My.Namespace.functionName", window, arguments);
Tenga en cuenta que puede pasar en el contexto que desee, por lo que esto haría lo mismo que arriba:
executeFunctionByName("Namespace.functionName", My, arguments);
Para agregar a la respuesta de Jason Bunting, si está usando nodejs o algo (y esto también funciona en dom js), puede usar this
lugar de window
(y recuerde: eval es malo :
this[''fun''+''ctionName'']();
Puede llamar a la función javascript dentro de eval("functionname as string")
tampoco. Como a continuación: (eval es pura función javascript)
function testfunc(){
return "hello world";
}
$( document ).ready(function() {
$("div").html(eval("testfunc"));
});
Ejemplo de trabajo: https://jsfiddle.net/suatatan/24ms0fna/4/
Si desea llamar a una función de un objeto en lugar de una función global con la window["functionName"]
. Puedes hacerlo como;
var myObject=new Object();
myObject["functionName"](arguments);
Ejemplo:
var now=new Date();
now["getFullYear"]()
Sin usar eval(''function()'')
, podría crear una nueva función usando la new Function(strName)
. El siguiente código fue probado usando FF, Chrome, IE.
<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>
Solo necesita convertir su cadena en un puntero por window[<method name>]
. ejemplo:
var function_name = "string";
function_name = window[function_name];
Y ahora puedes usarlo como un puntero.
Solo pensé en publicar una versión ligeramente modificada de la muy útil función de Jason Bunting .
Primero, he simplificado la primera declaración al proporcionar un segundo parámetro a slice () . La versión original funcionaba bien en todos los navegadores excepto en IE.
En segundo lugar, he reemplazado esto con el contexto en la declaración de retorno; de lo contrario, esto siempre apuntaba a la ventana cuando se estaba ejecutando la función de destino.
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);
}
Sorprende no ver ninguna mención de setTimeout.
Para ejecutar una función sin argumentos:
var functionWithoutArguments = function(){
console.log("Executing functionWithoutArguments");
}
setTimeout("functionWithoutArguments()", 0);
Para ejecutar la función con argumentos:
var functionWithArguments = function(arg1, arg2) {
console.log("Executing functionWithArguments", arg1, arg2);
}
setTimeout("functionWithArguments(10, 20)");
Para ejecutar la función de espacio de nombre profundo:
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);
También hay alguna manera muy útil.
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
};
Todas las respuestas asumen que se puede acceder a las funciones a través del alcance global (también conocida como ventana). Sin embargo, el OP no hizo esta suposición.
Si las funciones se encuentran en un ámbito local (también conocido como cierre) y no están referenciadas por algún otro objeto local, mala suerte: tiene que usar eval () AFAIK, vea llamar de forma dinámica la función local en javascript
Un detalle más sobre las publicaciones de Jason y Alex. Me pareció útil agregar un valor predeterminado al contexto. ¿Solo pones context = context == undefined? window:context;
context = context == undefined? window:context;
Al principio de la función. Puede cambiar la window
a cualquiera que sea su contexto preferido, y entonces no necesitará pasar la misma variable cada vez que lo llame en su contexto predeterminado.
todo lo que tiene que hacer es usar un contexto o definir un nuevo contexto donde residen las funciones. no está limitado a la window["f"]();
Aquí hay un ejemplo de cómo uso alguna invocación dinámica para algunos servicios REST.
/*
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.
Si desea generar toda la función a partir de una cadena, esa es una respuesta diferente. también tenga en cuenta que no está limitado a un solo espacio de nombres, si su espacio de nombres existe como my.name.space.for.functions.etc.etc.etc
la última rama de su espacio de nombres contiene la función como my.name.space.for.functions.etc.etc["function"]();
Espero eso ayude. H.
¡¡¡TEN CUIDADO!!!
Se debe tratar de evitar llamar a una función por cadena en JavaScript por dos razones:
Razón 1: algunos ofuscadores de código arruinarán tu código ya que cambiarán los nombres de las funciones, haciendo que la cadena no sea válida.
Razón 2: Es mucho más difícil mantener el código que usa esta metodología, ya que es mucho más difícil localizar los usos de los métodos llamados por una cadena.
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'');
Una solución más OOP ...
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);
}