Почему IE обнуляет переменные window.ABC? - PullRequest
25 голосов
/ 05 января 2011

При запуске следующего блока кода, 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 в IE?

Ответы [ 3 ]

26 голосов
/ 05 января 2011

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

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

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

В частности, во втором теге скрипта IE сначала ищет операторы var, он находит 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>
10 голосов
/ 05 января 2011

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

[Изменить]

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

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

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

[/ Edit]

Спасибо@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(...)

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

3 голосов
/ 05 января 2011

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

  1. var являющимся оператором
  2. В JS нет области действия блока
  3. Операторы выполняются до выполнения кода

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...