在Javascript中动态调用函数

11
我希望能够根据字符串动态调用函数,例如 "User.find"。如果该函数存在,则脚本将在 User 对象中调用 find() 函数。以下是我的尝试:
 var User = {};
 User.find = function(){
     return 1;
 }

 var input = 'User.find';
 var some_data_array = {name: 'John Doe'};
 var method = input.toString().split('.');
 var nameObj = method[0].substring(0,1).toUpperCase() + method[0].substring(1);
 var methodToCall = method[1];

 nameObj.call(methodToCall, some_data_array);

但它始终返回:
 nameObj.call(methodToCall, some_data_array);
 TypeError: Object User has no method 'call'

有什么想法吗?由于这是一个node.js问题,所以我不能使用window,脚本在浏览器中无法执行。


当涉及到动态性时,请尝试使用 eval - King King
这就是我在这里询问的原因。我不知道如何从动态对象中调用函数。 - Madnx
4
@KingKing:不要使用 eval - SLaks
3
是的,我希望避免使用 eval。 - Madnx
@SLaks 在某些情况下它是可用的,事实上如果没有它,你无法解决问题(我不是指在这种情况下,但可能在某些情况下)。 - King King
显示剩余7条评论
4个回答

15

您完全误解了call()

call()允许您使用不同的this调用方法。

您想按名称获取属性:

object[methodName](arg1, arg, ...);

谢谢回答,但对我没有用:http://jsfiddle.net/74kmm6bp/ 或者可能我不知道如何使用它。 - Madnx
这不是OP想要的。至少OP的问题现在不清楚。他甚至没有任何正确的对象在这里,也没有提及方法的一些引用(只有方法名)。 - King King
@Codel96:nameObj是一个字符串。要通过该名称获取全局变量,请使用相同的语法:window[nameObj] - SLaks
@Codel96:然后将可能被访问的变量放入一个单独的对象中,并使用它。这样更安全。 - SLaks
1
@KingKing: 这是因为JSFiddle将代码包装在一个函数中,所以那些是局部变量。 - SLaks
显示剩余2条评论

3

您实际上可以实现这一点。首先,您需要获取定义您的命名空间/函数/对象的scope

例如,在您的代码中,我会假设它是window

因此,对您的代码进行一些修改将产生所需的结果:

var User = {};
User.find = function(x){
    alert(x);
}

 var input = 'User.find';
 var some_data_array = {name: 'John Doe'};
 var method = input.toString().split('.');
 var nameObj = global[method[0]];
 var methodToCall = method[1];

 nameObj[methodToCall](some_data_array.name);

标记使用global[]。这是它开始的地方。

[编辑] * 修改代码,使用global而不是在nodejs中使用的window


问题是我不能使用window,因为它在服务器端使用node。 - Madnx
@Codel96:这就是为什么我写了 - 你需要获取 scope,而我的示例使用的是 window 范围。你可能会有一个不同的范围(即 global)。我会更改代码。 - sudipto
好的,谢谢你的回答。我会尝试一下。我认为我还是会选择SLaks的答案,因为它更容易操作数据,但这个答案对我很有帮助。;) - Madnx
范围通常是您定义“用户”的地方,在大多数情况下由“this”给出。 - sudipto
请注意,为客户端提供在global及其子类上调用任意方法的可能性与使用eval一样糟糕。 - Bergi
正确。这就是为什么我提到要获取范围的原因。该代码旨在说明如何使用 @Codel96 的现有代码,该代码似乎正在使用全局范围。 - sudipto

0
你想要做的是访问全局对象。
这应该可以工作:
var User = {};
User.find = function(){
    return 1;
}

var input = 'User.find';
var some_data_array = {name: 'John Doe'};
var method = input.toString().split('.');
var nameObj = method[0].substring(0,1).toUpperCase() +method[0].substring(1);
var methodToCall = method[1];

"use strict";
var global = (1,eval)("this");
alert(global[nameObj][methodToCall](some_data_array));

它在jsfiddle中无法工作,请在控制台中运行。编辑:我认为这是因为fiddle如何运行JS,它没有在全局范围内声明“User”对象。 - EvilZebra
这是我得到的:TypeError: 对象#<Object>的属性'connect'不是函数 - Madnx

0

有几种方法可以得到所需的结果。在这种情况下,只需使用匿名函数即可非常简单,如下所示,将包含在objName.name中的字符串参数传递进去:

var f = function(oName){
  if (oName == 'John Doe') {
     return 1;
  }   
 };


 var objName = {name: 'John Doe'};
 
console.log( f( objName.name ) );

如果楼主更喜欢使用对象的调用方法,下面的代码也可以满足要求:

var myObj = {
  myFunc: function() {
    if (this.name == 'John Doe') {
      return 1;
    }
  }
}

var objName = {
  name: 'John Doe'
};

console.log(myObj.myFunc.call(objName));

需要注意的几点事项。myObj 调用其方法 myFunc() 并传入对象参数 objName。方法中 this 的目的是读取属性 name,因为它被绑定到对象 objName 上,所以具备这种能力。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接