0

Within IE9, do the following:

Array.prototype.$$isArray = true;
var popup = window.open( .... );
// later
var x = ['test'];
alert( x[0] );        // Shows "test"
alert( x.$$isArray ); // Shows "true"

Within the popup HTML do:

function test( x ) {
  alert( x[0] );        // Shows "test"
  alert( x.$$isArray ); // Shows "undefined"
)

Why do the results differ? Is this a bug in IE?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Steffen Heil
  • 4,286
  • 3
  • 32
  • 35
  • Looks like you've run into the IE `isArray()` bug and got your wires a little crossed somewhere. I've updated my [`isArray` solution](http://stackoverflow.com/questions/1058427/how-to-detect-if-a-variable-is-an-array/4029057#4029057), feel free to see if that solves your problem. – Andy E Jul 10 '11 at 13:58

2 Answers2

1

No, it's not a bug (at least, not in the browser), and it's not just IE.

Each document the browser shows has its own global environment, including prototypes for the basic objects. They're each a blank slate. The Array constructor in one document is not the same as the Array constructor in another document, and those contructors don't share a common prototype property; the environments are disconnected. That's why instanceof doesn't work well in multi-document web applications.

Consider this example (live copy):

window.onload = function() {

  document.getElementById('theButton').onclick = function() {
    var wnd, start;

    display("Adding property to <code>Array.prototype</code>");
    Array.prototype.__foo = "bar";

    display("Testing property locally, <code>[].__foo = " +
            [].__foo +
           "</code>");

    display("Opening pop-up window");
    wnd = window.open("http://jsbin.com/omopaw/3");

    display("Waiting for window to load...");
    start = new Date().getTime();
    checkWindowLoad();

    function checkWindowLoad() {
      var a, b;

      if (typeof wnd.getArray === "undefined") {
        if (new Date().getTime() - start > 10000) {
          display("Error, 10 seconds and the window hasn't loaded");
        }
        else {
          setTimeout(checkWindowLoad, 10);
        }
        return;
      }

      display("Window loaded, getting array from it");
      a = wnd.getArray();
      display("<code>a</code> contents: " + a.join(", "));
      display("<code>a.__foo = " + a.__foo + "</code>");
      display("<code>a instanceof Array</code>? " +
              (a instanceof Array));
      display("<code>wnd.Array === Array</code>? " + 
              (wnd.Array === Array));

      display("Creating <code>b</code>");
      b = [3, 4, 5];
      display("<code>b.__foo = " + b.__foo + "</code>");
      display("Passing <code>b</code> to the popup, look there for the result.");
      wnd.callback(b);
    }
  };

  function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = msg;
    document.body.appendChild(p);
  }

};

That opens a pop-up window and then retrieves an array from it. But the array we receive was constructed by a different Array object than the one in our window, and so doesn't have the additions we made to our Array.prototype. Then it creates an array instance that does have those additions and passes it to the pop-up, which sees the additions correctly (since the object continues to reference its original prototype):

Output in the main window:

Adding property to Array.prototype
Testing property locally, [].__foo = bar
Opening pop-up window
Waiting for window to load...
Window loaded, getting array from it
a contents: 1, 2, 3
a.__foo = undefined
a instanceof Array? false
wnd.Array === Array? false
Creating b
b.__foo = bar
Passing b to the popup, look there for the result.

...and in the pop-up:

I'm the popup.
Received x: 3,4,5
x.__foo = bar

You'll see that output both on IE (I specifically tested IE9, but it works on IE7 and I'm sure others as well) and on other browsers.

The environments in the two different windows can talk to each other, but they don't have shared globals; the Array.prototype in the parent window is not inherited by the child window in any way.

You've said in the comments than when you pass the array from the main window to the child window the additions "disappear." (There's nothing in your code showing you doing that.) We can see from the above that in fact, the object maintains its relationship with its prototype correct and does show the additions, so I suspect (with apologies) it's just an error in your code.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I Know that those windows use different prototypes but I set that property on the source prototype. Even the built-in debugger shows the additional property in its inspector... – Steffen Heil Jul 10 '11 at 23:18
  • @Steffen: There is no "source prototype" (at least, no publicly-accessible one; there may be one buried in the JavaScript engine's implementation details). The `Array.prototype` you're writing to is for *that window only*. If you see your new property in the debugger, I can only assuming you're looking at the `Array.prototype` of the window you where you assigned the property, not the pop-up window. – T.J. Crowder Jul 11 '11 at 03:43
  • Each object is linked to a certain prototype. Changing the prototype even after creating the object, changes the (view of the) object. `var x = []; Array.prototype.y = 1; x.z = 2; alert(x.y+','+x.z);` alerts `1,2`. As soon as I pass `x` to another window and that window calls the same alert it shows `undefined,2`. That doesn't make any sense. I agree that this was different if I changed the Array prototype of the new window, because that has nothing to do with the variable x. – Steffen Heil Jul 11 '11 at 09:26
  • @Steffen: Yes, I understand how prototypical inheritance works. You never said anything about passing an *instance* from the parent window to the child, nor does your code show you doing that. But it should work, and the instance should maintain its association with its prototype and so retain any properties you added to that prototype. I've updated my example to show that working, which it does on IE9 and other browsers. With apologies, I think there's just a bug in your code. If you create a full, self-contained test case with all the code, I expect we can explain what's going wrong. – T.J. Crowder Jul 11 '11 at 09:53
0

Scripts that performed in popup has different context so if you try this in popup:

Array === window.top.Array // false
anton_byrna
  • 2,477
  • 1
  • 18
  • 31