function foo(){
console.log('foo', this);
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
有没有办法知道是否使用正常调用或
call/apply
的方式调用了 foo()
?
http://jsfiddle.net/H4Awm/1/
function foo(){
console.log('foo', this);
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
call/apply
的方式调用了 foo()
?
http://jsfiddle.net/H4Awm/1/
Function.prototype.call
和 Function.prototype.apply
(并将另一个参数传递给函数),否则没有办法这样做 - 实际的内部机制( [[Call]]
内部函数)不提供任何方法来表示使用()
调用它。
比较一般函数调用和 Function.prototype.apply
的规范 - 每个调用函数的内部代码方式完全相同,并且没有设置任何外部属性,能够告诉您是否使用了该函数。
请参见内部函数 [[Call]]
的规范:
13.2.1
[[Call]]
当使用函数对象F的值的[[FormalParameters]]内部属性、传递的参数列表args和this值在10.4.3中描述的方式为函数代码建立新的执行上下文时,将调用函数对象F的
[[Call]]
内部方法,执行以下步骤:
- 让funcCtx成为使用F的[[FormalParameters]]内部属性的值、传递的参数列表args和this值为函数代码建立新的执行上下文的结果。
- 让result成为计算F的[[Code]]内部属性的值的FunctionBody的结果。如果F没有[[Code]]内部属性或其值为空的FunctionBody,则result为(normal,undefined,empty)。
- 退出执行上下文funcCtx,恢复先前的执行上下文。
- 如果result.type是throw,则抛出result.value。
- 如果result.type是return,则返回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 }]);
apply
传递了一个数组,而为 call
传递了一个对象。如果你同时为两者都传递一个对象会发生什么? - Qantas 94 Heavyfunction 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
也可能不起作用。
foo.call(this, { bar: 1 }));
和foo.apply(this, [{ bar: 1 }]));
对吧? - Matteo Tassinari