Pull to refresh

Поведения браузеров с typeof и toString

Reading time 3 min
Views 2.7K
Сегодня начал писать проект частью которого были неубиваемые таймеры с Воркерами, выдерживающие полный перебор clearTimeout/clearInterval. Одним из условий было, что воркер или прочие функции/объекты могут подменить перед запуском скрипта. Для этого я написал функции isNativeObject(), isNativeFunction(), каждая имеет с десяток условий и определяют подмену/не подмену функции/объекта и косвенных признаков указывающих на «мухлёж».

Но тут дело не в этих функциях и тем более не в моём проекте. Прогоняя всевозможные нативные объекты я наткнулся на вопиюще разное поведение браузеров при обработке объектов с typeof и toString.

Например, меня крайне поразил тот факт, что абсолютно все браузеры выдают разные значения на
Worker.prototype + "";
// FF 3.6 [xpconnect wrapped native prototype]
// Op 11 [object DedicatedWorkerPrototype]
// Sa 4 [object WorkerPrototype]
// Ch 10 [object Object]

Сафари во все нативные конструкторы и прототипы подсовывает Prototype, Constructor — [object WorkerConstructor], [object WorkerPrototype]

В статье описаны другие интересные случаи поведения браузеров с typeof и toString.

Firefox 3.6, Firefox 4


typeof Worker // function
Worker + "" // [object Worker] - не понятно почему [object ...] 
Worker.prototype + "" // [xpconnect wrapped native prototype] ???
// аналогично с XMLHttpRequest и FileReader

typeof localStorage.prototype // object - во всех других браузерах undefined
localStorage.prototype + "" // null

navigator.geolocation + "" // [object GeoGeolocation] - не понятно какие ещё геолокации есть кроме Geo- во всех остальных браузерах [object Geolocation]

Firefox оптимизирует константы, заменяет кавычки и выравнивает код в toString:
(function(){return'a'+'b';}).toString(); 
// function () { 
//     return "ab"; 
// }

Firefox выбрасывает исключение при попытке изменить navigator.userAgent

Opera 11


В опере более-менее хорошо с typeof и toString, но подозрительно следующее поведение:
Worker.prototype + "" // [object DedicatedWorkerPrototype] - Dedicated!
XMLHttpRequest.prototype + "" // [object XMLHttpRequestPrototype]
EventSource.prototype + "" // [object EventSourcePrototype]

Названия аналогичны Safari, кто у кого «перенял»?
Opera позволяет менять navigator.userAgent

Safari и Mobile Safari


Сафари кроме своих Prototype, Constructor префиксов имеет следующую особенность — все её нативные объекты имеют typeof === 'object', хотя некоторые (XHR и Worker) должны быть 'function'.
RegExp.prorotype + "" //  // - у всех кроме IE /(?:)/

Сафари не меняет navigator.userAgent и не выбрасывает исключение

IE 8


Из всего, что я проверял ИЕ смог опознать только XMLHttpRequest и RegExp, поэтому список для него не такой большой:
typeof XMLHttpRequest // object
XMLHttpRequest.prototype + "" // [Interface prototype object]
RegExp + "" // \nfunction RegExp() {\n [native code]\n}\n - к чему лишние переносы строк не ясно

RegExp.prorotype + "" //  // - как и у Сафари
typeof document.getElementById // object    o_O

IE 8 выбрасывает исключение при попытке изменить navigator.userAgent, IE 9 ведет себя как сафари.
В IE 9 поправлены все вышеперечисленные баги, кроме того, что в [native code] функциях до сих пор полно \n

Chrome 10 beta


Хром имеет всего лишь одну «фичу»:
Worker.hasOwnProperty("toString") // true - не понятно почему бы не брать с прототипа...

Хром как и сафари не меняет navigator.userAgent и не выбрасывает исключение

Это ещё не все


Сводная, полная таблица по браузерам и объектам: goo.gl/tD1jr
Код тестера: jsfiddle.net/azproduction/V4LeE

Заключение


Хотя все браузеры (не ие 8) проходят acid 3, но в них остается ещё много много багов в деталях. Фиксированные ответы на typeof и toString очень важны для JavaScript с его утиной типизацией.

В исследовании участвовали объекты: Worker, XMLHttpRequest, CanvasContext, CanvasContext3D, Storage, WebSocket, FileReader, EventSource, navigator.geolocation, HTMLElement, RegExp, querySelectorAll, getElementsByTagName, childNodes.
Браузеры: Firefox 4, Firefox 3.6, Opera 11, Safari, IE 8, IE 9, Chrome 10 beta, Mobile Safari iOS 4.2.1

По техническим причинам не могу добавить все мобильные браузеры. Не стал выделять отдельно разбор полетов с HTMLElement — во всех браузерах творится ерунда.

PS Буду благодарен тем, кто просканирует остальные мобильные браузеры (Chrome Mobile, Opera Mobile) — киньте выдачу тестера мне в ЛС. Если вы желаете добавить какой-то свой тест — добавьте его в конец тестера с ссылкой в комментарий — позднее я обновлю таблицу.

UPD Добавлен Firefox 4, IE 9 (спасибо hf35), Mobile Safari iOS 4.2.1, ws для Opera (спасибо SKYnv)
Добавлены querySelectorAll, getElementsByTagName, childNodes

UPD2 Добавлены ответы для каждого объекта на Object.prototype.toString(...)
Tags:
Hubs:
+34
Comments 8
Comments Comments 8

Articles