一、背景:
在JavaScript中,将一个函数作为参数传递给另外一个函数,然后在那个函数中调用传递过来的函数,是非常简单和直接的。如:
function sayHello() { alert("Hello"); }function invoker(functionName) { functionName(); }
invoker(sayHello);
在上例中,通过将函数名sayHello传递给invoker()函数,然后在invoker()函数体中直接调用传进去的函数。执行结果如下:
二、问题:
上例中,sayHello() 函数是不带参数的,所以比较简单。但是,如果我们改写sayHello()函数,让它变得更灵活些,接收两个参数,那么新的invoker()函数应该怎样写才能适应这种情况呢?即,如何才能够动态地调用任何函数呢?不管被调用的函数带不带参数,也不管它究竟需要多少个参数,我们希望都能够以统一的接口来调用。
三、解决方案:
利用JavaScript中Function类的apply()函数,以及结合使用arguments对象,来解决这个问题:
function say(msgTitle, msgBody) { alert(msgTitle + "\r\n" + msgBody); } function invoker(func) { var args = Array.prototype.slice.call(arguments); args.splice(0, 1); func.apply(window, args); } invoker(say, "hello", "world");
以上代码执行结果如下:
注意,上述代码中,有 var args = Array.prototype.slice.call(arguments) 语句,是为了将 arguments 对象转换成一个真正的 Array 对象的实例。
四、更多说明:
以上的invoker()函数,真正实现了灵活的动态调用。它接受的参数是,要被调用的函数名,然后是要被调用的函数的参数列表,这个参数列表有没有,个数是多少,都没有做限制,完全根据要被调用的函数的需求来。
更多例子:
function compute(a, b, c) { alert(a + b + c); } invoker(compute, 1, 2, 3); invoker(function (s) { alert(s.split("\r\n").length); }, "FirstLine\r\nSecondLine\r\nThirdLine");
最后一个例子,演示了可以直接传递匿名函数参数。