本文共 14706 字,大约阅读时间需要 49 分钟。
我有一个函数的名称作为字符串。 如何将其转换为函数指针,以便以后可以调用?
根据情况,我可能还需要将各种参数传递给该方法。
一些功能可能采用namespace.namespace.function(args[...])
。
还有一些非常有用的方法。
var arrayMaker = { someProperty: 'some value here', make: function (arg1, arg2) { return [ this, arg1, arg2 ]; }, execute: function_name};
有关Jason和Alex帖子的更多详细信息。 我发现将默认值添加到上下文很有帮助。 只是把context = context == undefined? window:context;
context = context == undefined? window:context;
在函数的开头。 您可以将window
更改为首选上下文,然后每次在默认上下文中调用此变量时都不需要传递相同的变量。
如果要使用window["functionName"]
调用对象的函数而不是全局函数。 你可以这样做;
var myObject=new Object();myObject["functionName"](arguments);
例:
var now=new Date();now["getFullYear"]()
您能不能只是这样做:
var codeToExecute = "My.Namespace.functionName()";var tmpFunc = new Function(codeToExecute);tmpFunc();
您也可以使用此方法执行任何其他JavaScript。
所有答案均假定可以通过全局范围(也称为窗口)访问这些功能。 但是,OP没有做出此假设。
如果函数位于本地范围(也称为闭包)中,并且未被其他本地对象引用,那么运气不好:您必须使用eval() AFAIK,请参见
要添加到Jason Bunting的答案中,如果您使用的是nodejs或其他内容(并且在dom js中也适用),则可以使用this
而不是window
(并记住:eval是邪恶的 :
this['fun'+'ctionName']();
小心!!!
一个人应避免使用JavaScript在字符串中调用函数,这有两个原因:
原因1:一些代码混淆器会破坏您的代码,因为它们会更改函数名称,从而使字符串无效。
原因2:维护使用此方法的代码要困难得多,因为查找字符串调用的方法的用法要困难得多。
惊讶地发现没有提到setTimeout。
要运行不带参数的函数:
var functionWithoutArguments = function(){ console.log("Executing functionWithoutArguments");}setTimeout("functionWithoutArguments()", 0);
使用参数运行函数:
var functionWithArguments = function(arg1, arg2) { console.log("Executing functionWithArguments", arg1, arg2);}setTimeout("functionWithArguments(10, 20)");
要运行深度命名空间的功能:
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);
我的代码中有一个非常相似的东西。 我有一个服务器生成的字符串,其中包含一个函数名,我需要将其作为第三方库的回调传递。 因此,我有一个接受字符串并向函数返回“指针”的代码,如果未找到则返回null。
我的解决方案与“ ” 非常相似,尽管它不会自动执行,并且上下文始终在窗口中。 但这很容易修改。
希望这会对某人有所帮助。
/** * 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;}
因此,就像其他人所说的,绝对最好的选择是:
window['myfunction'](arguments)
就像 ,如果函数的名称包含一个对象,它将无法正常工作:
window['myobject.myfunction'](arguments); // won't workwindow['myobject']['myfunction'](arguments); // will work
所以这是我的函数版本,它将按名称执行所有函数(包括或不包括对象):
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');
我认为,执行此操作的一种优雅方法是在哈希对象中定义函数。 然后,您可以使用字符串从哈希中引用这些函数。 例如
var customObject = { customFunction: function(param){...}};
然后,您可以致电:
customObject['customFunction'](param);
其中customFunction是与对象中定义的函数匹配的字符串。
使用ES6,您可以按名称访问类方法:
class X { method1(){ console.log("1"); } method2(){ this['method1'](); console.log("2"); }}let x = new X();x['method2']();
输出将是:
12
我无法抗拒提及另一个技巧, 如果您有数量不明的参数也作为包含函数名称的字符串的一部分传递,这将很有帮助 。 例如:
var annoyingstring = 'call_my_func(123, true, "blah")';
如果您的Javascript在HTML页面上运行,则只需要一个不可见的链接即可。 您可以将字符串传递给onclick
属性,然后调用click
方法。
<a href="#" id="link_secret"><!-- invisible --></a>
$('#link_secret').attr('onclick', annoyingstring);$('#link_secret').click();
或在运行时创建<a>
元素。
在不使用eval('function()')
您可以使用new Function(strName)
创建一个新函数。 以下代码已使用FF,Chrome,IE进行了测试。
另一个问题的答案显示了如何做到这一点:
基本上你可以说
window["foo"](arg1, arg2);
或许多其他人建议,您可以使用eval:
eval(fname)(arg1, arg2);
尽管这绝对是不安全的,除非您完全确定要评估的内容。
两件事情:
避免评估,这是非常危险和缓慢的
其次,函数是否存在无关紧要,“全局” -ness无关紧要。 可以通过xy['foo']()
或x['y']['foo']()
甚至window['x']['y']['foo']()
启用xyfoo()
window['x']['y']['foo']()
。 您可以像这样无限期地链接。
除非您绝对没有其他选择,否则不要使用eval
。
如前所述,使用以下方法将是最好的方法:
window["functionName"](arguments);
但是,这将不适用于名称空间的功能:
window["My.Namespace.functionName"](arguments); // fail
您将按照以下方式进行操作:
window["My"]["Namespace"]["functionName"](arguments); // succeeds
为了使操作更简单并提供一些灵活性,这里提供了一个便捷功能:
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);}
您可以这样称呼它:
executeFunctionByName("My.Namespace.functionName", window, arguments);
请注意,您可以根据需要传递任何上下文,因此与上述操作相同:
executeFunctionByName("Namespace.functionName", My, arguments);
最简单的方法是像has元素一样访问它
window.ClientSideValidations.forms.location_form
与...相同
window.ClientSideValidations.forms['location_form']
use thisfunction 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); }
看起来很基本:
var namefunction = 'jspure'; // Stringfunction jspure(msg1 = '', msg2 = '') { console.log(msg1+(msg2!=''?'/'+msg2:''));} // multiple argument// Results ur testwindow[namefunction]('hello','hello again'); // something...eval[namefunction] = 'hello'; // use string or something, but its eval just one argument and not exist multiple
存在其他类型的函数为类并查看示例nils petersohn
感谢您提供非常有帮助的答案。 我在项目中使用 。
我扩展了它以使其与可选的超时一起使用,因为设置超时的常规方法将行不通。 见
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 );
这里有几个executeByName
函数可以正常工作,除非名称包含方括号 -我遇到的问题-因为我动态生成了名称。 因此,上述功能将在诸如
app.widget['872LfCHc']['toggleFolders']
作为补救措施,我也使函数也考虑到了这一点,也许有人会发现它有用:
从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);}
为了获得更好的可读性,请同时检查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)
您可以在eval("functionname as string")
调用javascript函数。 如下所示:(eval是纯javascript函数)
function testfunc(){ return "hello world";}$( document ).ready(function() { $("div").html(eval("testfunc"));});
工作示例: :
这是我对Jason Bunting / Alex Nazarov出色答案的贡献,其中包括Crashalot要求的错误检查。
鉴于此(人为)的序言:
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(){};
然后执行以下功能:
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 );}
将允许您通过存储在字符串中的名称来调用javascript函数,该字符串可以是带名称空间的名称,也可以是不带参数的全局名称(包括Array对象),以提供有关遇到的任何错误的反馈(希望捕获它们)。
示例输出显示其工作方式:
// calling a global function without parmsexecuteFunctionByName( '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 parmsexecuteFunctionByName( 'ns.a' ); /* OUTPUT: namespace func passed: */// calling a namespaced function passing a string literalexecuteFunctionByName( '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 literalexecuteFunctionByName( 'n_s_a' ); /* OUTPUT: Uncaught n_s_a is not a function */// calling a non-existing function by string variableexecuteFunctionByName( n_s_a ); /* OUTPUT: Uncaught Snowden is not a function */// calling an existing function with the wrong namespace referenceexecuteFunctionByName( 'a', {} ); /* OUTPUT: Uncaught [object Object].a is not a function */// calling no functionexecuteFunctionByName(); /* OUTPUT: Uncaught function name not specified */// calling by empty stringexecuteFunctionByName( '' ); /* OUTPUT: Uncaught is not a function */// calling an existing global function with a namespace referenceexecuteFunctionByName( 'noSuchAgency', ns ); /* OUTPUT: Uncaught [object Object].noSuchAgency is not a function */
只是以为我会发布的稍微改动的版本。
首先,我通过向slice()提供第二个参数简化了第一条语句。 原始版本在IE以外的所有浏览器中均能正常工作。
第二,我曾与return语句的上下文代替这一点 ; 否则,在执行目标函数时, 它始终指向窗口 。
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);}
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');
更多OOP解决方案...
您要做的就是使用上下文或定义函数所在的新上下文。 您不仅限于window["f"]();
这是我如何对某些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.
如果要从字符串生成整个函数,那是一个不同的答案。 还请注意,如果您的命名空间以my.name.space.for.functions.etc.etc.etc
存在,则您不仅限于单个命名空间,命名空间的最后一个分支包含函数my.name.space.for.functions.etc.etc["function"]();
希望能帮助到你。 H。
这是我的Es6方法,它使您可以通过名称(如字符串或函数名称)来调用函数,还可以将不同数量的参数传递给不同类型的函数:
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
根据您所在的位置,您还可以使用:
this["funcname"]();self["funcname"]();window["funcname"]();top["funcname"]();globalThis["funcname"]();
或者,在nodejs中
global["funcname"]()
您只需要通过window[<method name>]
将字符串转换为指针。 例:
var function_name = "string";function_name = window[function_name];
现在您可以像使用指针一样使用它。
转载地址:http://kaogj.baihongyu.com/