Расширенная поддержка скриптов в IE9

До этого момента мы преимущественно говорили об улучшении быстродействия JavaScript в Internet Explorer 9, и не сказали почти ничего о новых или измененных функциях языка в движке "Chakra". Теперь, с выпуском третьего Platform Preview, мы можем рассказать вам о новых возможностях JavaScript, которые вы можете попробовать самостоятельно.

К слову, промышленным стандартом, определяющим язык JavaScript, является ECMA-262: ECMAScript Language Specification, разработанный и опубликованный Ecma International. В прошлом году исполнилось десять лет с момента представления третьей редакции ECMA-262 в декабре 1999 года. В декабре 2009 года Ecmaодобрила пятую редакцию ECMA-262, являющуюся преемником третьей редакции (четвертая редакция никогда не публиковалась), и в прошлом же году мы представили частичную поддержку ECMAscript 5 (ES5), добавив поддержку JSON в IE8. Помимо JSON, однако, ES5 стандартизирует множество важных расширений в языке JavaScript.

Новые возможности ES5 в IE9 Platform Preview

В режим документов Standards в IE9 добавлено множество важных возможностей ES5:

Новые методы массива. Было добавлено девять новых методов для работы над массивами. Два из них, indexOf и lastIndexOf, поддерживают поиск определенного значения в массиве. По существу они схожи с одноименными функциями, что выполняют операции над строками. Остальные семь методов массивов позволяют управлять массивами при помощи стиля функционального программирования. Например, нижеприведенный фрагмент кода использует новый метод фильтра для сбора элементов массива, отвечающих определенному условию:

//функция, проверяющая, включен или отключен объект элемента меню

 

function enabled(menuItem) {return menuItem.status==="enabled"};

 

 

//Предположим, что отдельные элементы меню имеют свойство состояния (status property) и

 

//что объект меню имеет свойство элементов (items property), которое является массивом.

 

//Создаем новый массив, содержащий лишь включенные элементы меню

 

var enabledItems=myMenu.items.filter(enabled);

Эти методы поддерживают различные виды обработки массива без явного программирования циклов. Кроме этого, все методы являются универсальными, то есть они могут быть применены к любому объекту с пронумерованными свойствами, а не просто объектам, созданным при помощи конструктора массива. Вы можете познакомиться с демонстрацией, использующей эти методы на веб-узле IE9 Test Drive. Также они обобщены в нижеприведенной таблице:

Метод массива Описание
indexOf Производит поиск первого появления определенного значения в массиве.
lastIndexOf Производит поиск последнего появления определенного значения в массиве.
forEach Применяет функцию к каждому элементу в массиве.
every Устанавливает, является ли определенное состояние истинным для всех элементов в массиве.
some Устанавливает, является ли определенное состояние истинным хотя бы для одного элемента в массиве.
map Применяет функцию к каждому элементу в массиве и создает новый массив с соответствующими результатами
filter Собирает в новый массив все элементы массива, для которых определенное состояние является истинным.
reduce Собирает одно значение, основанное на всех элементах в массиве.
reduceRight Собирает одно значение, основанное на всех элементах в массиве, обрабатывая их в обратном порядке.

Расширенная объектная модель. Важнейшей возможностью в этой области являются аксессоры. Их иногда также называют свойствами «getter/setter», поскольку они позволяют программистам, использующим JavaScript, контролировать, что происходит, когда программа получает или устанавливает значение свойства. Расширенная объектная модель ES5 также позволяет программистам контролировать, могут ли отдельные свойства менять свои значения, перечисленные выражениями for…in, а также могут ли свойства быть удалены или переопределены. Также она позволяет программисту контролировать, могут ли новые свойства быть добавлены в объект. ES5 также упрощает программистам, использующим JavaScript, создание объектов, наследуемых от определенного объекта-прототипа, а также просмотр определений свойств объекта и управление ими. Все эти возможности расширенной объектной модели доступны посредством свойств функции new конструктора объекта. Тем не менее, следует заметить, что текущий выпуск IE9 Platform Preview не поддерживает целиком использование этих методов с DOM-объектами.

Функция объекта Описание
Object.defineProperty Создает или изменяет определение свойства. Свойство может быть определено либо как свойство данных, либо как свойство аксессора, и для него могут быть установлены атрибуты записываемости (writable), перечисляемости (enumerable) и настраиваемости (configurable).
Object.defineProperties Создает или изменяет несколько определений свойств за одну операцию.
Object.create Создает новый объект с определенным прототипом и, опционально, набором определенных свойств.
Object.getPrototypeOf Получает прототип объекта от объекта-аргумента.
Object.getOwnPropertyDescriptor Возвращает полное описание атрибутов свойства объекта.
Object.getOwnPropertyDescriptor Возвращает массив, содержащий имена всех ненаследуемых свойств объекта.
Object.keys Возвращает массив, содержащий имена всех ненаследуемых свойств объекта, которые будут повторены выражением for…in.
Object.seal Запрещает добавление любых дополнительных свойств к объекту-аргументу и запрещает удаление или переопределение любых существующих свойств. Отдельные значения свойств по-прежнему могут быть изменены, если для них установлен атрибут записываемости writable.
Object.freeze Запрещает добавление любых дополнительных свойств к объекту-аргументу и запрещает удаление и переопределение любых существующих свойств. Кроме этого, значения существующих свойств не могут быть изменены.
Object.isSealed Проверяет, был ли объект запечатан при помощи Object.seal.
Object.isFrozen Проверяет, был ли объект зафиксирован при помощи Object.freeze.
Object.preventExtensions Запрещает добавление любых дополнительных свойств к объекту.
Object.isExtensible Проверяет, могут ли новые свойства быть добавлены к объекту.

Другие вычислительные методы и функции. Помимо добавления новых методов массива и объекта, ES5 добавляет или расширяет некоторые дополнительные методы, выполняющие полезные вычислительные операции.

Метод или функция Описание
String trim Удаляет пробелы из начала и конца строки.
Date toISOString Преобразовывает Date в формат строки, который должны поддерживать все реализации ES5.
Date.parse Существующая функция расширена для распознавания формата, созданного с помощью toISOString.
Date.now Возвращает числовое значение времени.
Array.isArray Достоверно проверяет, является ли объект массивом.
Function bind Задает фиксированные значения некоторым из аргументов функции.

ES5 также содержит ряд других незначительных изменений и технических исправлений в языке. Многие из них не повлияют на большинство программистов, поскольку они просто стандартизируют возможности, всегда поддерживавшиеся в браузерах. Примером таких функций является объединение строк в строчных литералах. Другое небольшое изменение представляет больше интереса. Такие зарезервированные имена как if, super и public могут теперь использоваться в качестве имен свойств объектных литералов и для доступа к свойству, следующему за точкой. Благодаря этому изменению программистам более не придется беспокоиться о длинных и произвольных списках слов, которые они не могли использовать в качестве имен свойств.

«Один скрипт, одна разметка»

Обновление JavaScript в IE9 не ограничивается поддержкой новых возможностей ES5. Сюда также относится стремление убедиться, что разработчики смогут использовать в IE9 ту же разметку и те же скрипты, что они используют в других браузерах. Ранее в этом году мы опубликовали документы, подробно описывающие отличия реализации JavaScript в IE8 от третьей редакции спецификаций ECMAScript. При разработке режима IE9 Standards мы обратили особое внимание на эти различия и внесли изменения, позволяющие IE9 исполнять те же скрипты, что и исполняют другие браузеры.

Исправленная проблема Пример
Выражения функций обрабатывались, как если бы они были объявлениями функций

 

function f() {alert("declaration")};

 

obj.callback=function f() {alert("expression")};

 

f(); // IE8 неверно выводит "expression"

Имена функций в выражениях функций не были локально определены в теле функции

 

var fact="the web is big";

 

Math.factorial=function fact(n)

 

{return n<=1?1:fact(n-1)};

 

alert(Math.factorial(9)); // IE8 вызывает исключение

Параметры конструкции слежения были видны во внешней области

 

var e = "outer";

 

try {throw "inner"} catch(e) {};

 

alert(e); // IE8 неверно выдает "inner"

Во многих случаях вызванное исключение времени выполнения было отлично от указанного в стандарте

 

var obj; //значение obj не определено

 

try {alert(obj.prop)}

 

catch (e) {

 

if (e instanceof ReferenceError) alert("correct")

 

else if (e instanceof TypeError) alert("IE8 wrong")

 

}

Закрывающие запятые в литералах массива добавлялись в длину массива

 

var len = [1,2,3,].length;

 

alert(len); //должно быть 3, IE8 выдает 4

Пустые элементы в литералах массива не приводили к разреженному массиву

 

var a=[0,,2,,4];

 

alert(a.hasOwnProperty(1));// IE8 неверно выдает значение true

Атрибут dontenum наследовался собственными свойствами

 

var obj={valueOf:0, toString:1,foo:2};

 

var n=0;

 

for (var p in obj) n++;

 

alert(n); // IE8 отображает 1, а должен 3

\v не распознавался как escape-последовательность из-за непечатаемых символов вертикальной табуляции

 

alert("\v"==="v");//IE8 выдает true, а должен false

 

alert("\v"==="\u000b");

 

//IE8 возвращает false, а должен true

Глобальный объект не наследовал из Object.prototype

 

alert(hasOwnProperty===undefined);

 

// IE8 неверно выдает true, а должен false

Не соответствующие подстроке круглые скобки в регулярных выражениях приводили к пустой строке вместо неопределенного значения

 

var x=/((a)|(ab))((c)|(bc))/.exec("abc");

 

// x должен быть:

 

// ["abc","a","a",undefined, "bc",undefined, "bc"]

 

// IE8 выдает: ["abc","a","a","","bc","","bc"]

toFixed некорректно округлял некоторые диапазоны значений

 

alert((0.09).toFixed(1));

 

// должно отображаться 0.1

 

// IE8 отображает 0.0

«Использование одинаковых скриптов» касается не только того, как скрипты могут исполняться в Internet Explorer. Сюда также относится стремление убедиться, что скрипты, которые вы разрабатываете и тестируете в IE, также будут работать в любых других соответствующих стандартам браузерах, которые могут использовать ваши пользователи. Одна из проблем, которая может препятствовать достижению этой цели, заключается в возможностях, поддерживающихся исключительно в IE и отсутствующих в других браузерах. Если такая функция не является принципиально важной для функциональности браузера и не имеет уникального значения, реализована в одном единственном браузере и, по-видимому, не станет частью веб-стандарта, то она представляет собой опасность для совместимости. Если вы непредусмотрительно используете такую функцию в скрипте, то пользователи не смогут работать с ним в других браузерах.

В реализации JavaScript в Internet Explorer исторически имеется несколько функций, подпадающих под эту категорию, которые мы решили исключить из IE9 Standards Mode. В основном это функции, добавленные в качестве расширений возможностей на ранних стадиях разработки IE. Однако они не были добавлены в другие браузеры, и сегодня становится очевидным, что они никогда не будут включены в стандарт ECMAScript.

Первой функцией в этой категории является возможность добавления точки с запятой после любого блока кода. Например, IE разрешал заявления типа "if", составленные следующим образом:

if (conditionMet) {performTrueAlternative()};

 

else {performFalseAlternative()};

Обратите внимание на точку с запятой в конце первой строки. Стандарт ECMAScript никогда не допускал постановки точки с запятой на такой позиции. Если вы попытаетесь загрузить скрипт, содержащий этот код, в любом браузере, отличном от IE, то в нем будет обнаружена ошибка синтаксиса, и скрипт не будет загружен. Первоначально эта функция была добавлена из-за желания быть предельно нестрогими в отношении того, что может исполнять IE – в том числе пропускать некоторые ошибки синтаксиса. К сожалению, желание быть нестрогими приводит к проблемам совместимости при запуске скрипта в других браузерах. В таких случаях лучше, чтобы было выведено сообщение об ошибке, и она исправлена разработчиком скрипта.

В IEтакже имеется ряд расширений к синтаксису объявления функции. Одно из расширений позволяет объявлениям функции напрямую определять свойства метода объекта. Например:

function String.prototype.firstChar() {return this.substring(0,1)};

означает то же самое, что

String.prototype.firstChar = function (){return this.substring(0,1)};

Другое расширение позволяло объявлению функции определять несколько имен функции. Например, код

function declaration,dcl() {return processDeclaration)()};

, который задает как короткое, так и длинное имя одной и той же функции. Ни одно из этих расширений не добавляет каких-либо новых возможностей, которые бы не могли быть выражены с помощью стандартных функций языка, они не стандартизированы, не поддерживаются другими браузерами, и мы исключили их из режима IE9 Standards.

Заметьте, что это не означает, что мы удалили все функции, присущие исключительно реализации JavaScript в IE. Некоторые функции жизненно необходимы в случаях, когда разработчику требуется получить доступ к уникальным возможностям Internet Explorer или Microsoft Windows. Например, сюда относятся возможности JavaScript, поддерживающие доступ к объектам ActiveX.

Тестирование прогресса

Первостепенной целью при разработке IE9 является обеспечение единой разметки, которую можно было бы использовать во всех браузерах, к чему, конечно, относится и JavaScript. Так как же мы узнаем о нашем продвижении к этой цели? В одной из предыдущих статей мы говорили об отношении Microsoft к разрабатываемому набору тестов JavaScript. Мы считаем, что организации, ответственные за веб-стандарты, должны опубликовать окончательный набор тестов, гарантирующий работу одинаковых скриптов и одинаковой разметки во всех браузерах. На данный момент стандартизированного набора тестов для JavaScript не существует. Комитет стандартов ECMAScript согласился разработать такой набор, и мы совместно с разработчиками других браузеров, являющихся членами Ecma, трудимся над этим. Этот набор тестов еще не завершен и не опубликован. Тем временем, более 1300 относящихся к ES5 тестов, которые мы используем и планируем предложить Ecma, доступно на веб-узле Internet Explorer Testing Center. В результате добавленной нами поддержки ES5, IE9 теперь проходит все шестнадцать тестов Acid3 в группе 6 (JavaScript).

Проверьте самостоятельно

Нам нужны ваши отзывы. Дайте нам знать при обнаружении ошибки в JavaScript. В особенности нас интересуют проблемы совместимости. Если вы используете стандартизированную возможность JavaScript, и в режиме Standards в IE9 Platform Preview она работает иначе, чем в других браузерах, возможно, вы обнаружили ошибку – сообщите о ней на Connect. Поскольку вышеописанные изменения относятся лишь к режиму IE9 Standards, веб-узлы, работающие в режимах совместимости, не отражают этих изменений и продолжают вести себя по-прежнему.

Наконец, внимательно просмотрите ваш код на использование определения браузера для известных различий или ошибок JavaScript в IE, поскольку, скорее всего, оно более не будет работать в режиме IE9 Standards. Это уже не тот же самый старый JavaScript в IE.

Аллен Вирфс-Брок (Allen Wirfs-Brock),

Инженер-разработчик языка JavaScript в Microsoft.