Подтвердить что ты не робот

Почему переменные IE nuke 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?

4b9b3361

Ответ 1

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

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

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

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

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

  • Сохраняйте код в том же теге script
  • Не инициализировать переменные с помощью window.hiYa
  • Если вы не контролируете один из сценариев, убедитесь, что script, который использует 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 initialized to undefined here
            var hiya;
            if( false ) {
                hiya = 1;
            }
            document.write( "typeof(hiya) = "+ typeof(hiya) );
        </script>
    </body>
</html>

Итак, если вы поместите все в один тег script, это будет то, что будет с кодом (после того, как движок 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>

Ответ 2

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

[изменить]

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

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

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

[/Edit]

Благодаря @TimDown и @JuanMendes, указывающим на то, что проблема с написанием свойства объекту window является объявлением переменной.

Проблема:

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

Объяснение:

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

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

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

Что он делает, делая

В 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

То, что вы встретили, связано с:

  • var является выражением
  • В JS нет области блока
  • Заявления выполняются до запуска кода

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

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