How to check if a function is called using a call / apply

function foo(){ console.log('foo', this); } foo(); foo.call({ bar: 1 }); foo.apply([{ bar: 1 }]); 

Is there any way to find out if foo() was called using a regular call or call/apply ?

http://jsfiddle.net/H4Awm/1/

+7
javascript
source share
6 answers

Not. You cannot determine if a function is called from call/apply or usually.

They are not magical creatures, all they do is set the arguments and the meaning of this . There is a subtle difference when it comes to undefined / undeclared values, but that is.

All .apply and .call do in ES5:

Returns the result of calling the internal method fun [[Call]], providing thisArg as this value and argList as a list of arguments.

It sets the caller internal attribute correctly, so something naive like this will not work.

+3
source share

Unless you override Function.prototype.call and Function.prototype.apply (and pass another argument to your function), there is no way to do this - the actual internal mechanics (the internal [[Call]] function) provides no way to signal that it is being called using () .

Compare the specification of calling common functions with Function.prototype.apply - each call to the internal function code is done in exactly the same way, and there is no external set of properties that can give you a call using this or not.

See the specification of the internal function [[Call]] :

13.2.1 [[Call]]

When the internal [[Call]] method for an object of function F is called with this value and a list of arguments, the following steps are performed:

  • Let funcCtx be the result of creating a new execution context for the function code using the value of the internal property F [[FormalParameters]], the arguments passed to List args and this value, as described in 10.4.3.
  • Let the result be the result of evaluating FunctionBody, which is the value of the internal property F [[Code]]. If F does not have an internal [[Code]] property or if its value is empty FunctionBody, the result will be (regular, undefined, empty).
  • Close the funcCtx execution context by restoring the previous execution context.
  • If result.type is throw, then throw result.value.
  • If result.type is return, then return result.value.
  • Otherwise, result.type should be normal. Return undefined.

There is no need to change the operation of the function from whether it is called using call / apply or not - the only thing that changes what it does is the arguments for the function itself and that this should be inside the function.

+2
source share

I hope this solves your problem:

 function foo(){ console.log('foo', this); if (typeof this.length === "number") { //function has been apply } else { //function has been call } } foo(); foo.call({ bar: 1 }); foo.apply([{ bar: 1 }]); 
+1
source share

Try something like this:

 function foo(){ console.log('foo', this); console.log( arguments ); } Function.prototype._apply = Function.prototype.apply; Function.prototype.apply = function(ths,args){ args.unshift('apply'); this._apply(ths,args); }; foo(); foo.call(this, { bar: 1 }); foo.apply(this, [{ bar: 1 }]); 
+1
source share

Dirty, dirty hack:

 function foo() { var isNatural = !/foo\.(call|apply)/.test("" + foo.caller) console.log(isNatural ? "foo()" : "foo.{call,apply}()") } function caller1() { foo() } function caller2() { foo.call(null, { bar: 1 }) } function caller3() { foo.apply(null, [{ bar: 1 }]) } caller1() caller2() caller3() 

This is just food for thought. Do not use it in production.

+1
source share

I can't think of a reason why you should check this out, but you can check by comparing this === window as that default area (assuming it is based on the Javascript browser), but it can be faked just by calling foo like therefore foo.call(window) , which is basically what usually calls foo() .

It also probably won't work using window for functions that are properties of other objects or prototypes.

-one
source share

All Articles