4

I open a window, and want to perform some calculation on some condition. Problem is in IE, only first call of test (from ready) is performed from new window, but subsequent calls of test (set with setTimeout) are executed in parent window and not for new window (i.e. win).

It works fine in FF.

illustrating code (this code is in parent window):

var win = window.open(some_url, window_name, argument_string);

with (win) {
    function test() {
        alreadyrunflag += 1;
        if (alreadyrunflag < 10) {
            window.setTimeout(function() { test(); }, 500);
        }else { 
            //perform calculation
        }
    }

    jQuery(win.document).ready(function() {
        alreadyrunflag = 0
        test();          
    });
}
Shanta
  • 262
  • 1
  • 4
  • 15
  • Why did you place a function declaration inside a `with` statement? Did you declare the `alreadyrunflag`? You don't need to prefix the `setTimeout` call with `window.`, it is a global member anyway. You don't need to wrap your function call inside a function. Just `setTimeout( test, 500 )` is OK. – Šime Vidas Oct 28 '10 at 11:10
  • yes I declare alreadyrunflag in with block – Shanta Oct 28 '10 at 11:16
  • You declare it in with block? What does that mean? Are you declaring it like so: `var alreadyrunflag;`. If yes, is that declaration in the same scope as the code above? – Šime Vidas Oct 28 '10 at 11:39

2 Answers2

5

I would strongly recommend against using with in this situation (and, frankly, almost any other). Instead, simply write win. everywhere necessary. Like Eric Meyer, I'm not a huge fan of "considered harmful" essays, but this one by Douglas Crockford I'm in full agreement with.

with modifies the "scope chain" in a way that it takes a seriously advanced knowledge of JavaScript to understand fully. See Crockford's essay for details. It also introduces speed penalties (though granted, while I've heard people rant about them, I doubt the costs are really that high). The effects on maintainability are just unacceptable. Also, you can't use it in the new strict mode (MDC link), which is a useful mode that helps you avoid some common bugs.

In this case, it seems to me that the scope chain should resolve in the way you're expecting (and the way Firefox apparently is doing it), but frankly I'm not shocked at all that IE's JScript implementation doesn't handle it the same way. And/or it may be an issue with which jQuery ends up getting used (the one in the opening window or the one in the just-opened window; you can't be sure, and it would be timing-dependent...yuck).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    Indeed. E.g., look at `window.setTimeout`: this might resolve to `win.window.setTimeout`, or just `window.setTimeout`. – Marcel Korpel Oct 28 '10 at 10:56
  • Why IE is so (rude)! (its from my experience of javascript problems with IE.) – Shanta Oct 28 '10 at 10:58
  • 1
    @Shanta: IE does have serious issues, there's no question. :-) A lof of it improved in IE8 and the signs are good for IE9. Finally. But in fairness to Microsoft, let's remember that IE is also the reason we have several really useful features (Microsoft's IE innovations that have since been adopted by other browsers -- and by the W3C -- include the basis of Ajax [`XMLHttpRequest`] and `innerHTML`, without which a lot of the current web would be a lot harder to write). So okay, others probably would have done it if Microsoft hadn't, but still, they *did* -- and they did it very early on... – T.J. Crowder Oct 28 '10 at 11:01
  • @Marcel: A *very* good point. It would resolve to `win.window.setTimeout` (in a compliant implementation) but that's not how most of us would read it! And the same thing applies to `jQuery` -- is that the jQuery in the outer window, or the `jQuery` in the inner window? Odds are it would depend on timing (whether the new window had finished retrieving and parsing the jQuery script file). **Yuck** – T.J. Crowder Oct 28 '10 at 11:02
  • 1
    I totally agree with you about those innovations (after all, IE 6 was in its days a real improvement over many other browsers), but why on earth couldn't they implement there own `innerHTML` in a consistent way? Oh, and Shanta's braces weren't mismatched, as I erroneously thought, though a line without a statement (only a comment) doesn't get interpreted as an `else` statement (but of course this is only an example, the real code obviously includes a statement (block)). – Marcel Korpel Oct 28 '10 at 11:39
4

Putting a function declaration in a structure like if, for or with—anywhere other than directly inside a function body or global scope—is invalid in ECMAScript on a basic grammar level. Browsers typically let you get away with it, but what actually happens when you do varies from browser to browser, so you should never rely on it.

This case demonstrates one of the problems: in Firefox, the function statement is interpreted as the non-standard Mozilla JavaScript extension FunctionStatement, which treats it as if you'd used a FunctionExpression, evaluated inline when you expected.

But in IE, the function statement is interpreted in the same way as a kosher FunctionDeclaration and ‘hoisted’: evaluated at the start of the function that contains it. It does not gain the with statement's value as an extra scope (and even if it did, win hasn't been assigned yet, so you'd be putting undefined on the scope chain!).

So you could get around it by using the FunctionExpression explicitly:

with (win) {
    test= function() { ... };
}

But I'd seriously not recommend it. As TJ said, with absolutely sucks. It's abolished in ECMAScript Fifth Edition's Strict Mode. Don't use it. (And the timing issues mentioned in the comments. Yuck indeed.)

If you really want to inject test into the child window, say so directly: win.test= function() { ... };. However, I don't see any need to do so here. You can perfectly well look at the child window from outside without having to put a copy of the function in a property of the child window. Even if you do so, it won't change the scope of the code in the function. And giving documents a copy of functions from other documents is dodgy as in IE, if a document is unloaded, all the functions defined in that document break.

bobince
  • 528,062
  • 107
  • 651
  • 834