Как отзывы на предварительную версию платформы IE9 поменяли стандарт JavaScript

Когда мы впервые представили планы по Internet Explorer Platform Previews, то отмечали что «разработчики и те, кто интересуется стандартами и веб-разработкой, могут оценить функциональность новой платформы и заблаговременно оставить отзыв». Сейчас мы ежедневно получаем многочисленные отзывы и используем их для улучшения IE9. Однако иногда влияние отзывов выходит за пределы только IE9. Вот история о том, как недавний отзыв привел к корректировке нового стандарта JavaScript – ECMAScript 5th Edition (ES5).

Стандарт ES5 был официально представлен в декабре 2009 года, и третья предварительная версия IE9 стала первой широко распространенной версией, в которой были реализованы некоторые тонкие детали спецификации ES5. Стандарт ES5 разрабатывался с условием совместимости с существующими веб-сайтами, и международный технический комитет европейской ассоциации производителей ЭВМ TC39 старался избежать любых изменений, которые могут повлиять на безопасность и нарушить существующий код JavaScript. Однако в мире программного обеспечения не существует ничего совершенного, поэтому с третьим выпуском IE9 Platform Preview нам было интересно узнать о любых проблемах совместимости ES5 с существующими сайтами.

Вскоре после выхода третьей предварительной версии мы получили сообщение о том, что в ней некорректно работают некоторые веб-приложения, использующие библиотеку jQuery. Мы проследили эту проблему вплоть до конкретного метода API библиотеки, который в некоторых случаях допускает вызовы метода Object.prototype.toString без предварительной проверки аргумента на значение null или undefined. Конкретно, некоторые вызовы этого метода jQuery:

isFunction: function( obj ) {

return toString.call(obj) === "[object Function]";

},

выдают ошибку: «TypeError: Object expected». Последующий анализ показал, что toString в этом коде является встроенным методом Object.prototype.toString и что сбой происходит, когда isFunction вызывается со значением аргумента undefined. Почему ошибка случается в IE9, но не в предыдущих версиях или других браузерах? Потому что третья предварительная версия платформы IE9 фактически подчиняется спецификации ES5 Object.prototype.toString.

В соответствии с прежними версиями спецификации ECMAScript, вызов любого встроенного метода, использующего в качестве this значение null или undefined, передает методу «глобальный объект» (в браузерах это объект DOM window) как его значение this. Это открывает ряд потенциальных брешей в безопасности инфраструктур, нацеленных на безопасную поддержку гибридных веб-приложений.

Спецификация ES5 изменила ситуацию так, что значения null или undefined не заменяются объектом window, и определение каждого встроенного метода было обновлено, главным образом, в части получения этих значений, как их параметров this. Технический комитет ECMAScript попробовал сделать это при условии совместимости для нормального использования и генерации исключений в случаях, когда это невозможно. undefined был определен в ES5 для генерации таких исключений. Это и создает проблему совместимости, описанную выше.

Проблема может быть легко решена изменением кода jQuery (выделено красным цветом):

isFunction: function( obj ) {

return obj && toString.call(obj) === "[object Function]";

}

Команда jQuery действительно собирается внести это изменение. Однако такое изменение не исправит тысячи локальных копий jQuery которые уже существуют в интернете. Учитывая широкое распространение jQuery, становится ясно, что ES5 содержит серьёзную проблему совместимости. Понятно как мы можем изменить исполнение реализацию ES5 в IE9, чтобы решить проблему. Можно вернуть такое же строковое значение ("[object Object]"), которое возвращает IE8 в этой ситуации. Это решение не создаст каких-либо проблем в безопасности, которые ES5 старается исключить. Однако мы не хотим в одностороннем порядке вносить это изменение в нашу реализацию нового стандарта. Это не решит проблем совместимости и интероперабельности: если в IE проблема будет решена одним способом, то в других браузерах – другим или вообще не решена.

Как только мы поняли проблему и пути её решения, я описал её в дискуссионной группе TC39 es5-discuss как ошибку обратной совместимости. Моё первое сообщение по поводу данной проблемы было размещено в 17:51 25 июня в пятницу. К 22:00 был получены ответы от членов TC39, представлявших Apple, Mozilla и Google. Все согласились, что данная проблема относится к совместимости и должна быть исправлена, и что генерация исключения в данном случае не обязательна и не желательна. Мы также первоначально согласились с тем, что идея о возврате такого же строкового значения, что и в ES3 в данном случае выглядит как хорошая идея. Однако из дальнейших сообщений после выходных мы поняли, что не все браузеры могут вернуть в данной ситуации "[object Object]", а также некоторые другие экспериментальные значения, включая "[object Window]" и "[object Global]". Предлагалось возвращать "[object null]" и "[object undefined]". Показалось, что это лучшее решение, поскольку оно не только снимает проблему с jQuery, но также четко различает null и undefined от фактических объектов. Также это лучше для интероперабельности браузеров, так как она требует, чтобы браузеры выдавали идентичные результаты, а не так, как в ситуации с ES3, когда различные браузеры выдают различные результаты.

Ко вторнику в дискуссионной группе был достигнут консенсус и последовало окончательное предложение. Как только мы пришли к согласию, я отдал измененную спецификацию undefined нашей группе разработчиков IE9 JavaScript, чтобы они смогли создать исправление вовремя и широкого протестировать его со следующим предварительным выпуском IE9. Разработчики Mozilla также сообщили, что они внедрят это исправление в следующую бета-версию Firefox. Я также внес изменения в официальный список ошибок для ES5, так что это изменение спецификации зафиксировано там (параграф 15.2.4.2).

Веб-стандарты являются комплексным продуктом, имеющим отношение к ПО, и, как все программы, они содержат ошибки. Иногда лучшим способом найти и исправить ошибки совместимости является реализация и развёртывание этого стандарта среди широко используемых браузеров. Обычно такое бывает в ранних выпусках, как в случае с предварительными версиями IE9. Так что когда вы, как разработчик веб-страниц, составляете отзывы на такие выпуски, вы не только предоставляете отзыв на определенный браузер, но также на новые и внедряющиеся стандарты, которые он реализует. Конечно, чтобы такой отзыв дал результат, разработчикам браузеров и авторам стандартов необходимо иметь возможность и готовность быстро отреагировать на отзывы, которые рапортуют о существенных проблемах. Быстрая ответная реакция на проблемы с ES5 jQuery toString и другие проблемы с ES5 показывает, как разработчики браузеров и другие члены TC39 могут работать совместно для обеспечения большей совместимости и интероперабельности в интернете. Но все это становится возможным благодаря вашим отзывам. Так что, пожалуйста, держите нас в курсе.

Аллен Вирфс-Врок (Allen Wirfs-Brock)
Архитектор языка JavaScript Microsoft