使用Function.prototype.apply设置javascript回调范围

时间:2011-03-25 00:06:20

标签: javascript scope apply

每次在JavaScript中声明回调时,必须手动设置对象的范围是令人沮丧的,但这是生活中的事实。我想知道我是否可以通过传递[mycallback] .apply作为回调,并将范围对象作为参数来实现,如下所示:

var f = function() { console.log(this.x); };
var o = {x: 3};
setTimeout(f.apply, 1000, o);

据我所知,这应该以o作为范围调用f,但是Chrome会给我“未捕获的TypeError:Function.prototype.apply在[object DOMWindow]上被调用,它是一个对象,而不是一个函数”。为什么这不起作用?

3 个答案:

答案 0 :(得分:5)

出于同样的原因,您需要首先“设置范围”。只有apply函数被发送到setTimeout,其与函数f的关联将丢失。因此,Javascript会将全局对象window分配给this,就像在任何其他情况下一样。

值得注意的是apply虽然是本机函数,但在某种程度上并不特殊或神奇,并且在this的设置中以与用户定义函数一致的方式运行变量

答案 1 :(得分:4)

@ MooGoo的回答是正确的,但也许需要更多的解释。

当你在apply上调用f这样的函数时:

f.apply(ctx, args);

...然后您在apply

的上下文中执行f

但是当你将apply的引用传递给函数时,就像这样:

setTimeout(f.apply, 1000, o);

...这就是你所做的一切:传递对函数f.apply的引用。这相当于传递Function.prototype.apply,因为:

console.log(f.apply === Function.prototype.apply); // true

f中与window.setTimeout的任何连接都将丢失。它接收对apply的通用Function.prototype函数的引用。而已。没有背景。

因此,与未设置显式上下文的任何其他情况一样,调用apply函数时将window作为其上下文对象。

答案 2 :(得分:-1)

试试这个:

var f = function() { console.log(this.x); };
var o = {x: 3};
setTimeout(function(){f.apply(o)}, 1000);

适合我。

设置超时需要一个函数。但由于apply是一个内置函数,你无法看到它背后的本机代码,它可能不会充当“函数”对象。