我今天在IE8中遇到了一个问题(注意我只需要支持IE)我似乎无法解释:使用命名的匿名函数处理程序时detachEvent不起作用。
document.getElementById('iframeid').attachEvent("onreadystatechange", function onIframeReadyStateChange() {
if (event.srcElement.readyState != "complete") { return; }
event.srcElement.detachEvent("onreadystatechange", onIframeReadyStateChange);
// code here was running every time my iframe's readyState
// changed to "complete" instead of only the first time
});
我最终发现改变onIframeReadyStateChange以使用arguments.callee(我通常会避免)而是解决了这个问题:
document.getElementById('iframeid').attachEvent("onreadystatechange", function () {
if (event.srcElement.readyState != "complete") { return; }
event.srcElement.detachEvent("onreadystatechange", arguments.callee);
// code here now runs only once no matter how many times the
// iframe's readyState changes to "complete"
});
给出了什么?!第一个代码段不应该正常工作吗?
答案 0 :(得分:10)
第一个代码段不应该正常工作吗?
是的,可以说它应该。但事实并非如此。 :-)幸运的是,有一个简单的解决方法(比arguments.callee
更好,有问题[见下文])。
问题在于命名函数表达式(NFE,这就是你所拥有的)在JScript(IE)或其他几种实现中无法正常工作。 Yuriy Zaytsev(kangax)对NFE进行了彻底调查,并撰写了this useful article关于他们的信息。
命名函数表达式是指为函数指定名称和使用函数语句作为右侧值(例如,赋值的右侧部分,或将其传递给函数如attachEvent
),如下所示:
var x = function foo() { /* ... */ };
这是一个函数表达式,并且该函数已命名。可以说它应该工作,但在野外的许多实现中,包括IE的JScript,它没有。命名函数可以工作,匿名函数表达式可以工作,但不能命名函数表达式。 (编辑我不应该说不能正常工作,因为在某些方面他们会这样做。我应该说正常 ;更多在Yuriy的文章和my answer to your follow-up question中。)
相反,你必须这样做:
var x = foo;
function foo() { /* ... */ };
......毕竟,它确实会出现同样的事情。
所以在你的情况下,只需这样做:
document.getElementById('iframeid').attachEvent("onreadystatechange", onIframeReadyStateChange);
function onIframeReadyStateChange() {
if (event.srcElement.readyState != "complete") { return; }
event.srcElement.detachEvent("onreadystatechange", onIframeReadyStateChange);
// code here was running every time my iframe's readyState
// changed to "complete" instead of only the first time
}
这与您尝试的操作具有相同的效果,但不会遇到实施问题。
arguments.callee
(这稍微偏离主题,但是......)你应该避免使用arguments.callee
。在大多数实现中,使用它会带来大量性能开销,将函数调用减慢一个数量级(是的,真的;不,我不知道为什么)。它在ECMAScript 5的新“严格模式”中也是不允许的(“严格模式”主要是一件好事。)