admin 管理员组

文章数量: 1086019

I'm new to javascript, and came across the 'apply' method. As an exercise, I've tried to create a wrapper function for all functions, like the following snippet. 1. Why is this not working as expected, and 2. how can I create a wrapper function for all functions?

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

I'm new to javascript, and came across the 'apply' method. As an exercise, I've tried to create a wrapper function for all functions, like the following snippet. 1. Why is this not working as expected, and 2. how can I create a wrapper function for all functions?

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
Share Improve this question asked Oct 21, 2012 at 5:07 YeonhoYeonho 3,6235 gold badges40 silver badges62 bronze badges 1
  • 1 Interesting, I never realized that doing <function> + <number> will convert the function into a string. JavaScript, always full of surprises. – Matt Greer Commented Oct 21, 2012 at 5:19
Add a ment  | 

5 Answers 5

Reset to default 4

It's because the arguments object in funcWrapper is [function sum(num1, num2){ return num1 + num2; }, 2, 3], the first argument is the function that you pass. The arguments object is all of the arguments that you pass to the function.

The solution is to exclude the first argument which is the object. Usually in javascript, people use the slice method of the arrays. Well you might ask yourself that arguments is an object, and doesn't have that method. But we can do the following workaround:

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

In the funcWrapper. Which again you make it shorter by converting the first line to this:

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

You can also wrap that into a function like this:

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

And use it like this:

var args = _slice(arguments, 1);

Note that in ES6(Not implemented in browsers) this problem is solved by using rest parameters:

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

One more thing, that when you are trying to wrap constructors, make sure you also inherit the prototype too, or you fall into the same trap as this question: jQuery logger plugin

See this link here https://developer.mozilla/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments

"The arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length. For example, it does not have the pop method. However it can be converted to a real Array:"

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

try

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

By giving the full arguments object to .apply, you're also giving the function.

You need to exclude the first argument.

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

Another solution would be to do this:

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

But that gets a little confusing.

Because arguments contains [sum, 2, 3].

You would probably want to do this if you know the function to be called accepts 2 arguments:

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

If you don't know the number of arguments, probably:

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

return func.apply(this, arguments); should be return func.apply(this, Array.prototype.slice.call( arguments, 1 ));

本文标签: javascriptapply() not working as expectedStack Overflow