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 handl
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 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.)
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.
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).