ECMAScript 5 и JScript
Наибольшей новостью является та, что IE9pre3 имеет (почти) полную поддержку ES5. Под «полной поддержкой» подразумевается то, что уже сейчас включено большинство нового API, такого как, например, Object.create, Object.defineProperty, String.prototype.trim, Array.isArray, Date.now и много других дополнений. На сегодняшнее время IE9 поддерживает наибольшее количество методов, даже большее, чем последние версии Chrome, Safari и Firefox. Невероятно, не правда ли? :)
Вашему вниманию — полная таблица [не]совместимостей (заметьте то, что в ней перечислены результаты явно проведенных тестов, пока что всех соответствий нет).
Не хватает только
Некоторые вещи, на которые хочется обратить внимание:
ES5 Object.getPrototypeOf о хост-объектах, похоже, врет, постоянно возвращая null вместо правильного [[Prototype]]:
Object.getPrototypeOf(document.body); // null
Object.getPrototypeOf(document); // null
Object.getPrototypeOf(alert); // null
Object.getPrototypeOf(document.childNodes); // null
В последних браузерах Chrome, WebKit и Firefox, которые реализовывают Object.create — это работать не будет. Например, Chrome:
Object.getPrototypeOf(document.body) === HTMLBodyElement.prototype;
Object.getPrototypeOf(document) === HTMLDocument.prototype;
Object.getPrototypeOf(alert) === Function.prototype;
Object.getPrototypeOf(document.childNodes) === NodeList.prototype
… и так далее в том же духе.
Что интересно, связанные функции в IE9pre3 представлены как «function(){ [native code] }», что похоже тем самым на хост-объекты:
var bound = (function f(x, y){ return this; }).bind({ x: 1 });
bound + ''; // "function(){ [native code] }"
// в сравнении с
alert + ''; // "function alert(){ [native code] }"
Обратите внимание, что представление функции не включает ни идентификатор (f) и параметры (х, у), ни само тело функции (return this;). И это, конечно, лишний раз доказывает, что полагаться на функцию декомпиляции — не самая лучшая идея.
Класс символа пробела (а именно — /\s/) до сих пор не соответствует большинства «пробельных» символов (что предусмотрено спецификациями). Они включают «U+00A0», от «U+2000» до «U+200A», «U+3000», и так далее.
Тест доступен здесь. Любопытно, что ES5 String.prototype.trim как бы и «понимает» эти символы как пробелы очень даже и неплохо, производя пустую строку — как и ожидалось — что-то наподобии '\u00A0'.trim().
Приятно видеть, что ES5 Array.isArray — примерно в 20 раз быстрее, чем ручная обработка, например эта:
function isArray(o) {
return Object.prototype.toString.call(o) === "[object Array]";
}
Различие в скорости более-менее похожа и в других браузерах, применяющих сей метод.
Позорный, 10+ летний JScript NFE bug, который был описан раньше, наконец-то пофиксен:
var f = function g() { return f === g; };
typeof g; // "undefined"
f(); // true
Класс arguments [[Class]] теперь вычисляется как «Arguments», как ES5 и пределяет:
var args = (function(){ return arguments; })();
Object.prototype.toString.call(args); // "[object Arguments]"
DOM
К сожалению, вся инфраструктура хост-объектов еще очень похожа на ту, которая сейчас в IE8. Хост-объекты не наследуют Object.prototype, не сообщают о корректном typeof, и даже не имеют таких базовых свойства, как «length» или «prototype», которые должны иметь все объекты типа function:
alert instanceof Object; // false
typeof alert; // "object"
alert.length; // undefined
Из-за того, что они не наследуют Object.prototype, мы не располагаем каким-либо методов Object.prototype естественным образом:
alert.toString; // undefined
alert.constructor; // undefined
alert.hasOwnProperty; //undefined
Хост-объекты не могут наследовать Object.prototype. Но в большинстве современных браузеров, хост-объекты также наследуют от Function.prototype и поэтому имеют такие унаследованные методы из Function.prototype, как call и apply. В IE9pre3 такого не будет:
alert instanceof Function; // false
document.createElement instanceof Function; // false
alert.call; // undefined
Любопытно, что call и apply присутствует на некоторых базовых объектах, но они до сих пор не унаследованы от Function.prototype:
typeof document.createElement.call; // "function"
document.createElement.call === Function.prototype.call; // false
Хост-объект [[Class]] вообще далек от идеала. IE9pre3 на самом деле нарушает ES5, а это говорит, что объекты, имплементирующие [[Call]] (в других словах — являются вызываемыми) должны иметь [[Class]] как «Function» — даже если являются хост-объектами. В IE9pre3, alert — это вызываемый хост-объект, пока что он определяет свой [[Class]] как «Object», а не «Function», что есть, мягко говоря, не хорошо.
Object.prototype.toString.call(alert); // "[object Object]"
Object.prototype.toString.call(document.createElement); // "[object Object]"
IE9pre3 до сих пор путает атрибуты и свойства DOM-объектов, хотя и не так ужасно, как предыдущие его версии:
var el = document.createElement('p');
el.setAttribute('x', 'y');
el.x; // 'y'
el.foobarbaz = 'moo';
el.hasAttribute('foobarbaz'); // true
el.getAttribute('foobarbaz'); // 'moo'
Некоторые старые, юморные баги все еще можно увидеть в IE9pre3, такие как методы, возвращающие «string», когда применяется typeof, как пример:
typeof Option.create; // "string"
typeof Image.create; // "string"
typeof document.childNodes.item; // "string"
Необъявленные присваивания по-прежнему выбрасывают ошибку, когда элементы с тем же id присутствуют в DOM, чего уже не происходит с элементами с тем самым атрибутом name (как это было в предыдущих версиях):
<div id="foo"></div>
<a name="bar"></a>
…
<script>
foo = function(){ /* ... */ }; // Error
bar = function(){ /* ... */ }; // no Error
</script>
Похоже, как и в IE8, только Element и специфичные типизированные интерфейсы Element (HTMLDivElement, HTMLScriptElement, HTMLSpanElement, etc.) определяются одноименными глобальными свойствами. Node и HTMLElement до сих пор недоступны, а цепочка прототипа элемента, скорее всего, выглядит таким образом:
document.createElement('div');
|
| [[Prototype]]
|
v
HTMLDivElement.prototype
|
| [[Prototype]]
|
v
Element.prototype
|
| [[Prototype]]
|
v
null
…вместо того, что должно быть во всех остальных современных браузерах:
document.createElement('div');
|
| [[Prototype]]
|
v
HTMLDivElement.prototype
|
| [[Prototype]]
|
v
HTMLElement.prototype
|
| [[Prototype]]
|
v
Element.prototype
|
| [[Prototype]]
|
v
Node.prototype
|
| [[Prototype]]
|
v
Object.prototype
|
| [[Prototype]]
|
v
null
Метод getComputedStyle из DOM2 до сих пор недоступен, однако его значение таинственно равно null, а не undefined. То есть свойство на самом деле существует в объекте, но имеет значение null. Есть надежда, что это всего лишь заглушка и правильный метод будет добавлен перед финальным релизом.
document.defaultView.getComputedStyle; // null
'getComputedStyle' in document.defaultView; // true
Метод Array.prototype.slice теперь может преобразовывать определенные хост-объекты (например, NodeList) в массивы — то, что в большинства современных браузеров делалось довольно долгое время:
Array.prototype.slice.call(document.childNodes) instanceof Array; // true
На этом пока все.
Лично меня не покидает надежда, что ie9 с точки зрения веб-девелопера будет хорошим браузером. А это довольно упростит нам работу и сократит драгоценное время на отлавливание багов. И да будет так!