Ошибка переопределения элемента addEventListener в Firefox

Я пытаюсь переопределить объект Element addEventListener метод, в кросс-браузерной манере. Цель состоит в том, чтобы я мог загружать некоторые сторонние сценарии асинхронно, и эти сценарии вызывают этот метод преждевременно.

Я создал HTML-файл, который отлично работает в Chrome, но в Firefox я получаю следующее исключение:

"Недопустимая операция с объектом-прототипом WrappedNative" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)"

Если вы закомментируете строки в файле, которые изменяют методы INSTANCE, это работает. Но мне нужно сделать это на "типе класса" (то есть прототипе).

Мы ценим любые предложения.

Спасибо, Гайпо

Вот файл, который я создал

<html><body>
<img id="testImg" src="http://www.blaze.io/wp-content/themes/Blaze/images/header_logoB.png">
<script>
function myLog(msg) { "undefined" != typeof(console) && console.log("Log: " + msg); }
function customListener(type, event, useCapture) {
  // Register the event
  myLog('Registering event');
  this._origListener.apply(this, arguments);
}
// Also tried HTMLImageElement
Element.prototype._origListener = Element.prototype.addEventListener;
Element.prototype.addEventListener = customListener;

var img = document.getElementById("testImg");
// Uncommenting these lines works - but in the real case I can't access these objects
//img._origListener = img.addEventListener;
//img.addEventListener = customListener;
img.addEventListener('load',function() { myLog('load callback'); }, false);

</script>
</body>
</html>

2 ответа

Как говорит Марсель, это связано с тем, как выставляются хост-объекты. Проблема в том, что если вы переопределяете предопределенное свойство интерфейса, оно не изменяется в интерфейсах, которые наследуют от него (по крайней мере, в Firefox).

Хотя я согласен с замечаниями Марселя, на самом деле есть способ сделать это. Вы должны переопределить свойство минимально возможного интерфейса объекта, для которого вы хотите сделать это. В вашем случае это будет HTMLImageElement,

Это сделает свое дело:

(function() {
    var _interfaces = [ HTMLDivElement, HTMLImageElement /* ... (add as many as needed) */ ];
    for (var i = 0; i < _interfaces.length; i++) {
        (function(original) {
            _interfaces[i].prototype.addEventListener = function(type, listener, useCapture) {

                // DO SOMETHING HERE

                return original.apply(this, arguments);
            }
        })(_interfaces[i].prototype.addEventListener);
    }
})();
  1. Пожалуйста, используйте действительный Doctype, предпочтительно тот, который переводит браузеры в режим (почти) стандартов (<!DOCTYPE html> Это хорошо).

  2. typeof это оператор, вам не нужны скобки (но это не больно)

  3. Самое главное: не пытайтесь манипулировать DOM Element"s prototypeэто хост-объекты, и вы не можете полагаться на хост-объекты, раскрывающие какие-либо основные функциональные возможности JavaScript объекта. Хуже того, может быть снижение производительности, и вы можете сломать другие вещи. Держитесь подальше от этой техники. Для получения дополнительной информации прочитайте Что не так с расширением DOM.

Чего вы хотите добиться, чтобы ваши слушатели событий вызывались автоматически при использовании сторонних сценариев?

Другие вопросы по тегам