Когда мы впервые обнародовали наши планы по поводу предварительных версий IE9, мы сказали что «разработчики и люди, интересующиеся стандартами и веб-разработкой, смогут попробовать предварительную версию IE9 и высказать свои замечания и предложения относительно его работы». На данный момент мы ежедневно получаем отзывы и используем их для улучшения Internet Explorer 9. Однако обратная связь иногда касается не только IE9. Эта история о том, как недавний отзыв на Internet Explorer 9 Platform Preview вызвал изменение нового стандарта JavaScript – 5-ую редакцию EcmaScript.
Стандарт «EcmaScript 5» был официально принят в декабре 2009 года, и третья предварительная версия Internet Explorer 9 является нашей первой наиболее полной его реализацией. ES5 был спроектирован так, чтобы оставаться полностью совместимым с существующими сайтами, и технический комитет TC39 работал над тем, чтобы избежать любых не связанных с безопасностью изменений, которые могли бы привести в нерабочее состояние существующий JavaScript-код. Однако в мире программного обеспечения ничего совершенного не бывает, и, когда мы выпустили третью предварительную версию Internet Explorer 9, нам стало интересно, обнаружатся ли какие-нибудь проблемы совместимости с существующими сайтами, связанные с ES5.
Вскоре после выпуска предварительной версии нашего браузера мы получили несколько жалоб, что некоторые веб-приложения, использующие jQuery некорректно работают в IE9. Мы выяснили, что проблема заключалась в следующем методе JQuery API, который в некоторых случаях не работал, потому что код метода перед вызовом
Object.prototype.toString
не проверял переданное пользователем значение на null
или undefined
. В частности некоторые вызовы этого метода jQueryisFunction: function( obj ) {
return toString.call(obj) === "[object Function]";
}
* This source code was highlighted with Source Code Highlighter.
завершаются исключением:
“TypeError: Object expected”
. Дальнейший анализ показал, что toString
является встроенным методом Object.prototype.toString
, который вызывал сбой, когда isFunction
вызывала его со значением undefined
в качестве аргумента. Почему данное исключение возникало только в IE9, а не в более ранних версиях IE, а также в браузерах других производителей? Именно потому, что поведение третей предварительной версии IE9 в режиме стандартов действительно соответствует спецификации ES5 Object.prototype.toString
.Согласно предыдущей спецификации EcmaScript вызов встроенного метода с параметром
null
или undefined
приводит к передаче «глобального объекта» (у браузеров это объект DOM window
). Это открывает целый ряд потенциальных дыр в безопасности для фреймворков, цель которых обеспечить работу веб-приложений в безопасном режиме.Спецификация ES5 изменила данное поведение так, что передача
null
или undefined
не приводит к передаче в функцию объекта window
. Определение каждого встроенного метода было обновлено специально для решения проблемы получения этих значений в качестве значения this
. Технический комитет пытался сделать так, чтобы сохранить обратную совместимость для обычного использования и генерировать исключение в случае, когда это невозможно. Это создало проблему совместимости, описанную выше.Данная проблема может быть просто решена изменением кода jQuery:
isFunction: function( obj ) {
return obj && toString.call(obj) === "[object Function]";
},
* This source code was highlighted with Source Code Highlighter.
На самом деле команда jQuery планирует внести данное изменение. Однако данное изменение не затронет тысячи локально используемых библиотек jQuery существующих в вебе. Учитывая широкую распространенность jQuery, становится очевидным, что спецификация ES5 содержит серьезную проблему совместимости. Также вполне очевидно, каким образом мы можем изменить нашу реализацию ES5 в IE9 для решения проблемы. Мы можем просто вернуть строковое значение
"[object Object]"
, это же значение возвращает IE8 в данной ситуации. Такой фикс не добавляет проблем с безопасностью, которые старается решить ES5. Тем не менее, мы не хотим в одностороннем порядке вводить такое различие в нашу реализацию нового стандарта. Данное решение не поможет решению проблем совместимости и интероперабельности, если IE исправит эту проблему одним из способов, а другие браузеры не исправят вообще или сделают это иначе.Как только мы разобрались в проблеме и возможном решении, я поднял этот вопрос в списке рассылки для обсуждений комитета TC39. Мое первое сообщение по данной проблеме было опубликовано в 17:51 в пятницу 25 июня. К 22 часам уже были получены ответы от членов TC39, представляющих Apple, Mozilla и Google. Мы все согласились, что это была проблема совместимости, которую необходимо решить, и генерация исключения в данном случае не нужна и нежелательна. Изначально мы согласились с тем, что идея возврата строкового значения, как написано в ES3, для таких случаев выглядит как хорошая идея. Тем не менее, при дальнейшем обсуждении на выходных мы поняли, что не все браузеры в данный момент возвращают
"[object Object]"
, мы также рассматривали следующие значения "[object Window]"
и "[object Global]"
. Было предложено возвращать
"[object null]"
и "[object undefined]"
. Это решение, кажется, лучшее, поскольку не только устраняет такую проблему, как в случае jQuery, но и позволяет явно различать неопределенные и null-объекты. Данное решение также повышает интероперабельность браузеров, потому что требует, чтобы браузеры выдавали одинаковый результат, а не ситуацию ES3, которая приводила к различным результатам в различных браузерах.Во вторник данное решение было принято консенсусом как окончательное. Как только было достигнуто согласие, я передал пересмотренные спецификации
Object.prototype.toString
в команду разработчиков IE9 JavaScript, чтобы они могли внести исправления в текущую реализацию перед публичным испытанием следующей предварительной версии IE9. Mozillа также подтвердила, что примет данное исправление в следующей бета-версии Firefox. Я также обновил официальный список исправлений TC39 для ES5, это изменение описано в разделе 15.2.4.2 спецификации.Веб-стандарты – сложные программные артефакты, и как все ПО, они содержат ошибки. Иногда лучший способ найти и исправить ошибку совместимости, это реализовать стандарт в широко распространенном браузере. Данный способ обычно применяется в контексте выпуска ранних версий браузера, как в случае с Internet Explorer 9 Platform Preview. Таким образом, когда вы, как веб-разработчик отправляете фидбек на какой-либо конкретный браузер, вы также даете обратную связь тем стандартам, которые он реализует. Конечно, в таком случае, авторы браузеров и писатели стандартов должны иметь возможность быстро отреагировать на проблему. Быстрое реагирование на проблему ES5
Object.prototype.toString
, а также другие нестыковки, хороший пример того, как разработчики браузеров и другие члены TC39 могут и работают вместе для обеспечения совместимого и интероперабельного веба. Но все начинается с ваших отзывов, которым мы всегда рады.--
Allen Wirfs-Brock
Microsoft JavaScript Language Architect