javascript - How to check if a function is called using callapply - Stack Overflow

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

function foo(){
    console.log('foo', this);
}

foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);

Is there any way to know if foo() was called using a normal invoke or call/apply?

/

function foo(){
    console.log('foo', this);
}

foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);

Is there any way to know if foo() was called using a normal invoke or call/apply?

http://jsfiddle/H4Awm/1/

Share Improve this question edited Oct 29, 2013 at 13:42 Johan asked Oct 29, 2013 at 12:49 JohanJohan 35.2k62 gold badges187 silver badges305 bronze badges 1
  • 1 I'd say you mean foo.call(this, { bar: 1 })); and foo.apply(this, [{ bar: 1 }])); right? – Matteo Tassinari Commented Oct 29, 2013 at 12:53
Add a ment  | 

6 Answers 6

Reset to default 3

No. You can't detect if a function is called from call/apply or normally.

They're not magical beings, all they do is set the arguments and this value. There is a subtle difference when it es to undefined/undeclared values but that's it.

All .apply and .call do in ES5 is:

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

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

Unless you redefine Function.prototype.call and Function.prototype.apply (and pass another argument to your function), there is no way of doing so - the actual internal mechanics (the [[Call]] internal function) do not provide any method of signalling that it is called using ().

Compare the specification for a general function call and for Function.prototype.apply - each call the internal code of the function in exactly the same manner, and there is no external property set that is able to give you whether is called using that or not.

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

13.2.1 [[Call]]

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

  1. Let funcCtx be the result of establishing a new execution context for function code using the value of F's [[FormalParameters]] internal property, the passed arguments List args, and the this value as described in 10.4.3.
  2. Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property. If F does not have a [[Code]] internal property or if its value is an empty FunctionBody, then result is (normal, undefined, empty).
  3. Exit the execution context funcCtx, restoring the previous execution context.
  4. If result.type is throw then throw result.value.
  5. If result.type is return then return result.value.
  6. Otherwise result.type must be normal. Return undefined.

There is no provision to change the running of a function from whether it is called using call/apply or not - the only thing that changes what it does are the arguments for the function itself and what is this meant to be within the function.

I hope this solve 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 }]);

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 }]);

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()

It's just food for thought. Don't use it on production.

I can't think of a reason you should be checking for this but, you could check by paring this === window, as that's the default scope (assuming browser based Javascript), but this could be faked by simply calling foo like so foo.call(window) which is basically what calling foo() is doing normally.

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744113955a4559083.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信