2

我今天在 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"
});

是什么赋予了?!第一个片段不应该正常工作吗?

4

1 回答 1

10

第一个片段不应该正常工作吗?

是的,可以说应该。但事实并非如此。:-) 幸运的是,有一个简单的解决方法(并且比arguments.callee, 有更好的解决方法 [见下文])。

问题

问题是命名函数表达式(NFE,就是你所拥有的)在 JScript (IE) 或其他几个野外实现中不能正常工作。Yuriy Zaytsev ( kangax ) 对 NFE 进行了彻底的调查,并撰写了这篇关于它们的有用文章。

命名函数表达式是您给函数一个名称并将函数语句用作右侧值(例如,赋值的右侧部分,或将其传递给类似的函数attachEvent),如下所示:

var x = function foo() { /* ... */ };

那是一个函数表达式,函数被命名。可以说它应该可以工作,但在许多野外实现中,包括 IE 的 JScript,它没有。命名函数有效,匿名函数表达式有效,但命名函数表达式无效。(编辑我不应该说不工作,因为在某些方面他们会这样做。我应该说不正常工作;更多内容在 Yuriy 的文章和我对你后续问题的回答中。)

解决方案

相反,您必须这样做:

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 的新“严格模式”中也不允许这样做(“严格模式”主要是一件好事)。

于 2010-03-31T14:22:27.150 回答