问题描述
我今天在 IE8 中遇到了一个问题(注意我只需要支持 IE),我似乎无法解释:detachEvent
在使用命名的匿名函数处理程序时不起作用.
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
});
我最终发现将 onIframeReadyStateChange
更改为使用 arguments.callee
(我通常会避免使用)反而解决了这个问题:
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?
推荐答案
是的,可以说是应该的.但事实并非如此.:-) 幸运的是,有一个简单的解决方法(并且比 arguments.callee
更好,后者存在问题[见下文]).
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]).
问题是命名函数表达式(NFE,就是你在那里拥有的)在 JScript (IE) 或其他几个野外实现中无法正常工作.Yuriy Zaytsev (kangax) 对 NFE 进行了彻底调查并撰写了 这篇关于它们的有用文章.
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.
命名函数表达式是您给函数一个名称并使用函数语句作为右手值(例如,赋值的右手部分,或将其传递到函数类似于 attachEvent
),像这样:
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() { /* ... */ };
那是一个函数表达式,函数被命名.可以说它应该工作,但在许多实际实现中,包括 IE 的 JScript,它没有.命名函数有效,匿名函数表达式有效,但命名函数表达式无效.(编辑我不应该说不工作,因为在某些方面他们确实如此.我应该说不正常工作; 更多在 Yuriy 的文章和 我对你的后续问题的回答.)
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.)
相反,您必须这样做:
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.
(这有点偏离主题,但是...)您应该避免使用 arguments.callee
.在大多数实现中,使用它会带来巨大的性能开销,将函数调用减慢一个数量级(是的,真的;不,我不知道为什么).ECMAScript 5 新的严格模式"也不允许这样做(严格模式"通常是一件好事).
(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).
这篇关于detachEvent 不适用于命名的内联函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!