apply()无法按预期工作

时间:2012-10-21 05:07:07

标签: javascript

我是javascript的新手,并且遇到了'apply'方法。 作为练习,我尝试为所有函数创建一个包装函数,如下面的代码片段。 1.为什么这不能按预期工作,以及2.如何为所有函数创建包装函数?

function funcWrapper(func){
   return func.apply(this, arguments);
};

function sum(num1, num2){
   return num1 + num2;
}

funcWrapper(sum, 2, 3); 
// expected 5, but returns
// function sum(num1, num2){
//    return num1 + num2;
// }2

5 个答案:

答案 0 :(得分:3)

这是因为funcWrapper中的arguments对象是[function sum(num1, num2){ return num1 + num2; }, 2, 3],第一个参数是你传递的函数。 arguments对象是您传递给函数的所有参数。

解决方案是排除作为对象的第一个参数。通常在javascript中,人们使用数组的切片方法。那么你可能会问自己arguments是一个对象,并没有那个方法。但我们可以采取以下解决方法:

var args = Array.prototype.slice.call(arguments, 1);
return func.apply(this, args);

在funcWrapper中。通过将第一行转换为此,您可以将其缩短:

var args = [].slice.call(arguments, 1);
return func.apply(this, args);

你也可以把它包装成这样的函数:

function _slice(obj, start, end) {
  return [].slice.call(obj, start, end);
}

并像这样使用它:

var args = _slice(arguments, 1);

请注意,在ES6中(未在浏览器中实现),使用rest parameters解决了此问题:

function funcWrapper(func, ...args){
   return func.apply(this, args);
};

还有一件事,当你试图包装构造函数时,确保你也继承原型,或者你遇到与这个问题相同的陷阱:jQuery logger plugin

答案 1 :(得分:2)

点击此链接https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments

“arguments对象不是数组。它类似于数组,但除了长度之外没有任何数组属性。例如,它没有pop方法。但是它可以转换为实数数组: “

var args = Array.prototype.slice.call(arguments);

尝试

function funcWrapper(func){
     var args = Array.prototype.slice.call(arguments, 1); // skip func parameter
     return func.apply(this, args);
};

答案 2 :(得分:1)

通过将完整的arguments对象提供给.apply,您还可以提供该功能。

您需要排除第一个参数。

function funcWrapper(func) {
   var sliced = [].slice.call(arguments, 1);
   return func.apply(this, sliced);
}

另一种解决方案是:

function funcWrapper(func) {
   return func.call.apply(func, arguments);
}

但这有点令人困惑。

答案 3 :(得分:1)

因为arguments包含[sum, 2, 3]

如果你知道要调用的函数接受2个参数,你可能想要这样做:

return func.call(this, arguments[1], arguments[2]);

如果您不知道参数的数量,可能是:

var args = [];
for(var i = 1; i < arguments.length; i++)
    args.push(arguments[i]);
return func.apply(this, args);

答案 4 :(得分:1)

return func.apply(this, arguments);应为return func.apply(this, Array.prototype.slice.call( arguments, 1 ));