detachEvent 不适用于命名内联函数

发布于 2024-08-27 09:52:51 字数 1021 浏览 9 评论 0原文

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

什么给出了?!第一个片段不应该正常工作吗?

I ran into a problem in IE8 today (Note that I only need to support IE) that I can't seem to explain: detachEvent wouldn't work when using a named anonymous function handler.

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
});

I eventually figured out that changing onIframeReadyStateChange to use arguments.callee (which I normally avoid) instead solved the issue:

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"
});

What gives?! Shouldn't the first snippet work fine?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

微凉徒眸意 2024-09-03 09:52:51

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

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

问题 问题

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

命名函数表达式是指为函数指定名称并使用函数语句作为右侧值(例如,赋值的右侧部分,或将其传递给类似 < code>attachEvent),就像这样:

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

这是一个函数表达式,并且该函数被命名。可以说它应该能够工作,但是在许多野外实现中,包括 IE 的 JScript,它却不能工作。命名函数可以工作,匿名函数表达式可以工作,但命名函数表达式不行。 (编辑我不应该说不工作,因为在某些方面它们确实有效。我应该说不工作 ;尤里的文章和我对您的后续问题的回答中有更多内容.)

解决方案

相反,您必须这样做:

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

Shouldn't the first snippet work fine?

Yes, arguably it should. But it doesn't. :-) Fortunately there's an easy workaround (and a better one than arguments.callee, which has issues [see below]).

The problem

The problem is that named function expressions (NFEs, which is what you have there) do not work correctly in JScript (IE) or several other implementations out in the wild. Yuriy Zaytsev (kangax) did a thorough investigation of NFEs and wrote up this useful article about them.

A named function expression is where you give a function a name and use the function statement as a right-hand value (e.g., the right-hand part of an assignment, or passing it into a function like attachEvent), like this:

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

That's a function expression, and the function is named. Arguably it should work, but in many implementations in the wild, including IE's JScript, it doesn't. Named functions work, and anonymous function expressions work, but not named function expressions. (Edit I shouldn't have said don't work, because in some ways they do. I should have said don't work properly; more in Yuriy's article and my answer to your follow-up question.)

The solution

Instead you have to do this:

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

...which does, after all, come to the same thing.

So in your case, simply do this:

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
}

That has the same effect as what you were trying to do, but without running into implementation problems.

The problem with arguments.callee

(This is slightly off-topic, but...) You're right to avoid using arguments.callee. In most implementations, using it carries a massive performance overhead, slowing down the function call by an order of magnitude (yes, really; and no, I don't know why). It's also disallowed in the new "strict mode" of ECMAScript 5 (and "strict mode" is mostly a good thing).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文