Работа над IE8 с нарушенной реализацией Object.defineProperty

Рассмотрим следующий код, используя функцию ECMAScript5 Object.defineProperty:

var sayHi = function(){ alert('hi'); };
var defineProperty = (typeof Object.defineProperty == 'function');
if (defineProperty) Object.defineProperty(Array.prototype,'sayHi',{value:sayHi});
else Array.prototype.sayHi = sayHi;
var a = [];
a.sayHi();

Это работает для Chrome и Firefox 4 (где defineProperty существует), и работает для Firefox 3.6 (где defineProperty не существует). Однако IE8 поддерживает только defineProperty. В результате он пытается запустить метод Object.defineProperty, но затем не удается (без ошибок, отображаемых в браузере), и перестает запускать весь код JavaScript на странице.

Есть ли лучший способ обнаружить и избежать нарушения IE8, чем:

if (defineProperty){
  try{ Object.defineProperty(Array.prototype,'sayHi',{value:sayHi}); }catch(e){};
}
if (!Array.prototype.sayHi) Array.prototype.sayHi = sayHi;

Для любопытных я использую это в своей библиотеке ArraySetMath, чтобы определить методы, не перечисленные в массиве, в тех браузерах, которые поддерживают этот, с отступлением от перечислимых методов для старых браузеров.

Ответы

Ответ 1

Я не думаю, что есть лучший способ, чем прямой тест функции с try/catch. На самом деле именно эта команда IE рекомендует в этой недавней публикации переход к API ES5.

Вы можете сократить тест до всего лишь Object.defineProperty({}, 'x', {}) (вместо использования Array.prototype), но это незначительный каламбур; ваш пример проверяет точную функциональность (и поэтому имеет меньше шансов на ложные срабатывания).

Ответ 3

Я наткнулся на это раньше. ИМХО, использующее инструкцию try... catch слишком сильно.
Более эффективным было бы использование условной компиляции:

/*@[email protected](@_jscript_version>5.8)if(document.documentMode>8)@*/
Object.defineProperty && Object.defineProperty(Array.prototype,'sayHi',{value:sayHi});
/*@[email protected]*/ 

Ответ 4

У меня была такая же проблема (то есть Object.defineProperty в IE 8, являющейся только DOM, а не полной версией, как и другие браузеры), но это было для polyfill..

Anyhoo, я закончил использовать "функцию", чтобы проверить, не использовал ли я IE, но это не работает, но он работает на всех тестах, которые я мог бы сделать:

if (Object.defineProperty && !document.all && document.addEventListener) {
    Object.defineProperty(Array.prototype,'sayHi',{value:sayHi});
} else {
    Array.prototype.sayHi = sayHi;
}

поскольку IE <= 8 не имеет document.addEventListener, а document.all является запатентованным расширением Microsoft стандарта W3C. Эти две проверки эквивалентны проверке, является ли IE версией 8 или ниже.

Ответ 5

Array.prototype.sayHi = function(){ alert('hi'); };

try {
  Object.defineProperty(Array.prototype, 'sayHi', {
    value: Array.prototype.sayHi
  });
}
catch(e){};