Ошибка в JavaScript в IE9 для прототипов разных контекстов? - PullRequest
0 голосов
/ 10 июля 2011

В IE9 выполните следующие действия:

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

В всплывающем HTML-коде выполните:

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

Почему результаты отличаются? Это ошибка в IE?

Ответы [ 2 ]

1 голос
/ 10 июля 2011

Нет, это не ошибка (по крайней мере, не в браузере), и это не просто IE.

Каждый документ, который показывает браузер, имеет собственную глобальную среду, включая прототипы для основных объектов. Они все с чистого листа. Конструктор Array в одном документе отличается от конструктора Array в другом документе, и эти конструкторы не имеют общего свойства prototype; среды отключены. Вот почему instanceof плохо работает в многодокументных веб-приложениях.

Рассмотрим этот пример ( живая копия ):

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);
  }

};

Это открывает всплывающее окно и затем извлекает массив из него. Но массив, который мы получаем, был создан с помощью объекта Array, отличного от объекта в нашем окне, и поэтому не содержит добавлений, которые мы сделали к нашему Array.prototype. Затем он создает экземпляр массива, который имеет , имеет эти дополнения и передает его во всплывающее окно, которое правильно видит дополнения (поскольку объект продолжает ссылаться на свой первоначальный прототип):

Вывод в главное окно:

Добавление свойства к Array.prototype
Локальное тестирование недвижимости, [].__foo = bar
Открытие всплывающего окна
Ожидание загрузки окна ...
Окно загружено, получая массив из него
a содержание: 1, 2, 3
a.__foo = undefined
a instanceof Array? ложный
wnd.Array === Array? ложный
Создание b
b.__foo = bar
Передав b всплывающему окну, посмотрите на результат.

... и во всплывающем окне:

Я всплывающее окно.
Получено x: 3,4,5
x.__foo = bar

Вы увидите этот вывод как в IE (я специально тестировал IE9, но он работает и в IE7, и, я уверен, в других), так и в других браузерах.

Окружения в двух разных окнах могут общаться друг с другом, но у них нет общих глобалов; Array.prototype в родительском окне никак не наследуется дочерним окном.

В комментариях вы сказали, что при передаче массива из главного окна в дочернее окно добавления «исчезают». (В вашем коде ничего не показано, что вы делаете это.) Из вышесказанного видно, что на самом деле объект поддерживает свои отношения с его прототипом правильно и действительно показывает дополнения, поэтому я подозреваю (с извинениями) это просто ошибка в вашем коде.

0 голосов
/ 10 июля 2011

Сценарии, которые выполняются во всплывающем окне, имеют другой контекст, поэтому, если вы попробуете это во всплывающем окне:

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