переопределение глобальной функции в javascript

Я пытаюсь добавить свою собственную обработку ошибок в функцию JavaScript setTimeout. Следующий код отлично работает в chrome:

var oldSetTimeout = window.setTimeout;
window.setTimeout = function setTimeout(func, delay) {
    var args = Array.prototype.slice.call(arguments, 0);
    args[0] = function timeoutFunction() {
        var timeoutArgs = Array.prototype.slice.call(arguments, 0);
        try {
            func.apply(this,timeoutArgs);
        }
        catch (exception) {
            //Do Error Handling
        }
    }
    return oldSetTimeout.apply(this, args);
}

но в IE7 он превращается в рекурсивную функцию. Почему-то oldSetTimeout получает значение новой функции.

какие предложения?



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

2 ответов


это потому, что вы используете именованные функциональные выражения, которые неправильно реализованы в IE. Удаление имен функций устранит непосредственную проблему. См.kangax ' s отличная статья на эту тему. Однако, есть еще одна проблема, которую не так легко исправить.

в общем, не рекомендуется пытаться переопределить свойства объектов хоста (например,window, document или любой элемент DOM), потому что нет гарантия окружающей среды позволит это. Объекты хоста не связаны теми же правилами, что и собственные объекты, и по сути могут делать то, что им нравится. Также нет гарантии, что метод host будет Function "объект", и, следовательно,oldSetTimeout возможно, не всегда есть apply() метод. Это имеет место в IE, поэтому вызов oldSetTimeout.apply(this, args); не будет работать.

Я предлагаю следующее:

window.oldSetTimeout = window.setTimeout;

window.setTimeout = function(func, delay) {
    return window.oldSetTimeout(function() {
        try {
            func();
        }
        catch (exception) {
            //Do Error Handling
        }
    }, delay);
};

незначительное улучшение ответа Тима, чтобы еще больше имитировать оригинал:

window.oldSetTimeout = window.setTimeout;
window.setTimeout = function(func, delay) {
    return window.oldSetTimeout(function() {
        try {
            func();
        }
        catch (exception) {
            //Do Error Handling
        }
    }, delay);
};