function foo(){
console.log('foo', this);
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
有什么方法可以知道是否foo()
使用普通调用或调用call/apply
?
function foo(){
console.log('foo', this);
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
有什么方法可以知道是否foo()
使用普通调用或调用call/apply
?
不,您无法检测到函数是否被调用call/apply
或正常调用。
他们不是魔法生物,他们所做的只是设定论点和this
价值。当涉及到未定义/未声明的值时,存在细微差别,仅此而已。
返回调用func的[[Call]]内部方法的结果,提供thisArg作为this值,提供argList作为参数列表。
它正确地设置了内部caller
属性,所以像这样天真的东西是行不通的。
除非您重新定义Function.prototype.call
and Function.prototype.apply
(并将另一个参数传递给您的函数),否则没有办法这样做 - 实际的内部机制([[Call]]
内部函数)不提供任何方法来表明使用()
.
比较一般函数调用的规范和Function.prototype.apply
- 每次调用函数的内部代码的方式完全相同,并且没有外部属性集可以告诉您是否使用该函数调用。
请参阅内部功能的规范[[Call]]
:
13.2.1
[[Call]]
当
[[Call]]
使用 this 值和参数列表调用 Function 对象 F 的内部方法时,将执行以下步骤:
- 令 funcCtx 为使用 F 的 [[FormalParameters]] 内部属性的值、传递的参数 List args 和 10.4.3 中所述的 this 值为函数代码建立新执行上下文的结果。
- 让 result 是对作为 F 的 [[Code]] 内部属性的值的 FunctionBody 求值的结果。如果 F 没有 [[Code]] 内部属性,或者它的值为空 FunctionBody,则结果为(正常、未定义、空)。
- 退出执行上下文funcCtx,恢复之前的执行上下文。
- 如果 result.type 被抛出,则抛出 result.value。
- 如果返回result.type,则返回result.value。
- 否则 result.type 必须是正常的。返回未定义。
没有任何规定可以改变函数的运行是否使用call
/apply
或不调用 - 唯一改变它所做的是函数本身的参数以及函数中的this
含义。
我希望这能解决你的问题:
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 }]);
尝试这样的事情:
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 }]);
肮脏,肮脏的黑客:
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 === window
,因为这是默认范围(假设基于浏览器的 Javascript),但这可以通过简单地调用 foo 来伪造,foo.call(window)
这基本上就是调用foo()
做的很正常。
这也可能不适window
用于作为其他对象或原型属性的函数。