如何使用call / apply检查函数是否被调用

时间:2013-10-29 12:49:55

标签: javascript

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

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

有没有办法知道使用普通调用或foo()调用call/apply

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

6 个答案:

答案 0 :(得分:3)

没有。您无法检测是否从call/apply或正常调用函数。

他们不是神奇的存在,他们所做的只是设置参数和this值。对于未定义/未声明的值,有subtle difference,但就是这样。

ES5中的所有.apply.call都是:

  

返回调用func的[[Call]]内部方法的结果,将thisArg作为此值,将argList作为参数列表。

它正确设置了内部caller属性,因此像this这样天真的东西不起作用。

答案 1 :(得分:2)

除非你重新定义Function.prototype.callFunction.prototype.apply(并将另一个参数传递给你的函数),否则无法这样做 - 实际的内部机制([[Call]]内部函数)做不提供使用()调用它的任何信令方法。

比较general function callFunction.prototype.apply的规范 - 每个都以完全相同的方式调用函数的内部代码,并且没有外部属性集可以提供给你是否是使用或不使用。

请参阅内部函数[[Call]]的规范:

  

13.2.1 [[Call]]

     

当使用此值和参数列表调用Function对象F的[[Call]]内部方法时,将执行以下步骤:

     
      
  1. 让funcCtx成为使用F的[[FormalParameters]]内部属性的值,传递的参数List args以及10.4.3中描述的该值为函数代码建立新执行上下文的结果。
  2.   
  3. 让结果为评估作为F [[Code]]内部属性值的FunctionBody的结果。如果F没有[[Code]]内部属性或者其值为空FunctionBody,则结果为(normal,undefined,empty)。
  4.   
  5. 退出执行上下文funcCtx,恢复先前的执行上下文。
  6.   
  7. 如果result.type是throw,则抛出result.value。
  8.   
  9. 如果result.type为return,则返回result.value。
  10.   
  11. 否则result.type必须正常。返回undefined。
  12.   

没有规定更改函数的运行是否使用call / apply调用它 - 唯一改变它的功能的是函数本身的参数和什么是this意味着在函数内。

答案 2 :(得分:1)

我希望这能解决你的问题:

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

答案 3 :(得分:1)

尝试这样的事情:

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

答案 4 :(得分:1)

肮脏,肮脏的黑客:

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

这只是思考的问题。不要在生产中使用它。

答案 5 :(得分:-1)

我想不出你应该检查这个的原因但是,你可以通过比较this === window进行检查,因为这是默认范围(假设基于浏览器的Javascript),但这可以通过简单地调用来伪造foo就像这样foo.call(window),这基本上就是调用foo()正常做的事情。

对于属于其他对象或原型的函数,这也可能无法使用window