Почему IE обнуляет переменные window.ABC?

При запуске следующего блока кода, FF и Chrome выводятся typeof(hiya) = string в то время как выход IE7/8 typeof(hiya) = undefined,

<html>
    <body>
        <script type="text/javascript">
            window.hiya = 'hiya';
        </script>
        <script type="text/javascript">
            if( false ) {
                var hiya = 1;
            }
            document.write( "typeof(hiya) = "+ typeof(hiya) );
        </script>
    </body>
</html>

Каждое из следующих действий устраняет проблему:

  • Объединяя все в один <script> блок.
  • Удаление if блок.
  • Переименование var hiya = 1 в var hiya2 = 1,
  • Переименование var hiya = 1 в window.hiya = 1,
  • Переименование var hiya = 1 в hiya = 1,

Что происходит? Есть ли ошибка в IE?

3 ответа

Решение

IE тупой, он не признает, что window.varName а также var varName доступ к той же переменной в некоторых случаях.

Когда встречается новый тег script, он сначала инициализирует все переменные, объявленные с помощью var. Он не запускает оператор var (часть, которая инициализирует его как "hiya"). Он просто инициализирует его как неопределенное. Это не будет делать, если это было ранее объявлено с помощью var.

Если бы ваш код был в одном теге скрипта, эта ошибка не произошла бы. Кроме того, если первое объявление hiya было сделано с помощью var, эта ошибка также не возникнет.

В частности, в вашем втором теге сценария IE сначала ищет операторы var, он находит переменную var hiya = 1; Затем он говорит, что hiya ранее не инициализировался с помощью операторов var (IE тупой, другие браузеры распознают, что window.hiya делает то же самое) и инициализирует hiya, перезаписывая window.hiya перед выполнением любого кода.

Возможные решения:

  • Держите ваш код в том же теге скрипта
  • Не инициализируйте переменные с помощью window.hiYa
  • Если вы не управляете одним из сценариев, убедитесь, что на первом месте стоит сценарий, использующий var

Последнее замечание, чтобы уточнить, что парсеры JS делают с вашим кодом. Когда анализатор JS видит ваш код, он преобразует его в следующее:

<html>
    <body>
        <script type="text/javascript">
            window.hiya = 'hiya';
        </script>
        <script type="text/javascript">
            // IE is dumb, it doesn't recognize that hiya is already 
            // defined as window.hiya, so it's initialized to undefined here
            var hiya;
            if( false ) {
                hiya = 1;
            }
            document.write( "typeof(hiya) = "+ typeof(hiya) );
        </script>
    </body>
</html>

Таким образом, если вы поместите все в один тег сценария, это будет код (после того, как движок JS переместил операторы var на верх), так что вы можете видеть, что IE не может все испортить, так как ваш window.hiya назначение было бы после того, как var был перемещен на вершину.

<html>
    <body>
        <script type="text/javascript">
            var hiya;
            window.hiya = 'hiya';
            if( false ) {
                hiya = 1;
            }
            document.write( "typeof(hiya) = "+ typeof(hiya) );
        </script>
    </body>
</html>

Основная проблема может быть замечена здесь http://jsfiddle.net/Raynos/UxrVQ/ Я до сих пор не выяснил, почему IE перезаписывает window.hiya без проверки.

[Редактировать]

Из спецификации. Страница 38:

Для каждого VariableDeclaration или VariableDeclarationNoIn в коде создайте свойство объекта переменной, именем которого является идентификатор в VariableDeclaration или VariableDeclarationNoIn, значение которого не определено и атрибуты которого определяются типом кода. Если уже существует свойство объекта переменной с именем объявленной переменной, значение свойства и его атрибуты не изменяются.

Возможное объяснение может заключаться в том, что в глобальном масштабе IE различает window объект и variable object для глобальной области видимости при объявлении переменных. В качестве альтернативы установка свойства на window объект может не устанавливать одно и то же свойство на variable объект. Если вы можете найти формальную спецификацию JScript или найти источник IE, то мы можем точно выяснить, в чем причуды.

[/Редактировать]

Спасибо @TimDown & @JuanMendes за то, что проблема заключается в том, является ли запись свойства в объект окна оконным объявлением.

Проблема:

объявление переменной перемещается в верхнюю часть блока. Даже если код мертв. В IE по какой-то причине он объявит hiya как локальную переменную, даже если он классифицирует со свойством с тем же именем, хранящимся в окне.

Объяснение:

То, что происходит, это то, что вы объявляете переменную с именем hiya. Оператор var автоматически удаляется в верхнюю часть блока. Оператор if - это не блок, а функция. Поэтому, если код никогда не запускается в блоке, переменная все равно объявляется.

В Firefox он распознает, что window.hiya является объявлением hiya.

В IE объявление во втором скрипте перезаписывает его

Что он делает на самом деле

В Firefox:

// script block 1
var hiya; // window.hiya counts as a declaration
window.hiya = "hiya"; // set

// script block 2
if (false) hiya = 1;
document.write(...)

В IE:

// script block 1
window.hiya = "hiya";

// script block 2
var hiya; // redeclared here because window.hiya "isn't" a declaration
if (false) hiya = 1; 
document.write(...)

Решение - просто пространство имен. Вы используете одно и то же имя в двух местах и ​​обращаетесь к нему под двумя разными именами. Либо используйте разные имена, либо используйте замыкания для определения локальной области видимости.

То, с чем вы столкнулись, связано с:

  1. var быть заявлением
  2. Там нет блочной области видимости в JS
  3. Операторы выполняются до запуска кода

Так что происходит, что JavaScript будет выполнять var оператор прежде, чем что-либо еще, но он не будет оценивать выражение присваивания, поэтому hiya по умолчанию будет значение undefined,

Как уже сказал Рейнос, IE будет выполнять каждый скрипт самостоятельно, поэтому описанное выше поведение приведет к hiya быть неопределенным.

Другие вопросы по тегам