JavaScript中等价于PHP的call_user_func函数

5
我发现了这个主题并实现了它(请参见被接受的答案):
javascript equivalent of PHP's call_user_func() 然而,我在处理多个参数时遇到了问题。我意识到我正在将我的参数转换为字符串,并将其视为一个参数,但我不知道如何解决这个问题,因为我是动态创建参数的。
这意味着,在我的代码中,我定义了以下内容:
var a = new Array();
a[0] = new Array();
a[0][0] = 'alert';
a[0][1] = '\'Hello World\'';
a[1] = new Array();
a[1][0] = 'setTimeout';
a[1][1] = 'alert("goodbye world")';
a[1][2] = '20';

稍后,我会像这样给他们打电话:
    var j = 0;
    var len = 0;
    var fx = '';
    var params = '';
    for( i in a ){
        params = '';
        len = a[i].length;
        fx = a[i][0]; // getting the function name
        a[i].splice( 0, 1 ); // removing it from array
        if( len > 1 ){
            params = a[i].join(", "); // trying to turn the parameters into the right format, but this is turning it into strings I think
            params = params.replace(/\\'/g,'\''); // bc i was adding slashes with PHP
        }
        window[fx](params);
    }

我不必使用数组来完成这个任务。虽然我熟悉 PHP 面向对象编程,但我还没有尝试过 JS 面向对象编程,因此我不知道在那里是否有做到这一点的方法。
如果您能提供关于传递多个参数的任何帮助,将不胜感激。
谢谢。

1
window[fx].apply(obj, params) - Cheeso
2
你在这里自讨苦吃。首先:你不应该有一个包含代码的字符串数组,这是错误的。而且,更不要用正则表达式来解释这些字符串。你到底想做什么?此外:永远不要在数组上使用for .. in循环,也根本不应该使用new Array() - Tomalak
@Tomalak 抱歉,但那个建议是不可靠的。例如JSONP和服务器定义的回调将把函数作为字符串。按字符串名称检查和调用函数比运行eval更安全。就我个人而言,我同意正则表达式,但从技术上讲,它完全可行于此任务。在适当的时候使用for .. in,这经常发生。当您想要创建自己的容器原型时,使用new Array()非常方便。 - That Realty Programmer Guy
1
@GaretClaborn 没有冒犯的意思,但我已经对这场辩论感到非常疲倦了,而且这个帖子已经快 10 年了。你的「eval 不完全是坏的」和「在代码上使用正则表达式可以使 eval 更安全」也只是一种高度主观的立场。每一条编程建议都是如此。每一个「规则」只是一种惯例,通常来自更有经验的人们,他们发现做某些事情或避免某些事情是有益的。鼓励初学者在还有其他选择的情况下不要编写基于 eval 的解决方案是一个完全合理的观点,我已经阐明了理由。如果你不同意,也可以提出你的看法。 - Tomalak
1
回顾我9年前的代码,即使对我自己来说也相当尴尬。 - phpmeh
显示剩余6条评论
3个回答

14

首先要做的是:放弃你的整段代码,重新开始。你的方法不会让你达到想要的结果。(很遗憾,我不能告诉你想要什么结果,因为我无法理解你的示例。)

在JavaScript中有三种调用函数的方式。

function foo() { console.log(arguments); }

// 1. directly
foo(1, 2, 3);

// 2. trough Function.call()
foo.call(this, 1, 2, 3);

// 3. trough Function.apply()
var args = [1, 2, 3];
foo.apply(this, args);

callapply 是相似的。它们让您决定在函数内部 this 关键字指向哪个对象(这是重要的一点!)。

apply 接受一个参数数组,call 接受单个参数。

call() 最接近的东西是 PHP 的 call_user_func()。而 apply() 最接近的是 PHP 的 call_user_func_array()

JavaScript 对象与 PHP 数组有一些共同之处:它们都是键/值对。

// an anonymous function assigned to the key "foo"
var obj = {
  foo: function () { console.log(arguments); }
};

这意味着你可以使用点符号来访问对象属性:

// direct function call
obj.foo(1, 2, 3);

或者使用方括号表示法(注意对象键是字符串):

var funcName = "foo";
obj[funcName](1, 2, 3);
obj[funcName].call(obj, 1, 2, 3);
obj[funcName].apply(obj, [1, 2, 3]);
用方括号表示法可以动态选择对象属性。如果该属性恰好是一个函数,则apply()可以动态选择函数参数。
每个未声明为某些对象的属性的顶级函数将成为“全局”对象的属性。在浏览器中,全局对象是window。(因此我上面第一个代码块中的function foo()实际上是window.foo。)
请注意,this不像PHP那样工作。它将指向调用该函数的对象,而不是函数“所属”的对象。(在JavaScript中不存在真正的“所属”概念。可以模拟这种方式,但这只是一种惯例。)
使用直接调用(obj.foo(1,2,3)),this将指向obj。使用callapplythis将指向您想要的任何对象。这比初听起来更有用。大多数情况下,当您想动态调用函数时,您最终会使用apply

3

看看 Function.apply:

function test(a, b) { console.log([a, b]) }

test.apply(null, [1, 2]); // => [ 1, 2 ]

1
晚了一步,但是现在有了ES6,你可以简单地这样做:
function FunctionX(a,b,c,d){
    return a + b + c + d;
}

let fx = "FunctionX";
let params = [ 1, 10, 100, 200 ];

let answer = window[fx]( ... params);
let answer2 = globalThis[fx]( ... params );   // this is more cross-platform

解包您的参数数组


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