简体   繁体   中英

Bug in JavaScript in IE9 for prototypes of different contexts?

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?

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.

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

Array === window.top.Array // false

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM