最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Failure to override Element's addEventListener in Firefox - Stack Overflow

programmeradmin1浏览0评论

I'm trying to override the Element object's addEventListener method, in a cross-browser manner. The purpose is so that I can load some 3rd party scripts asynchronously, and those scripts call this method prematurely.

I created an HTML file that works perfectly in Chrome, but on Firefox I get this exception:

"Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)"

If you ment out the lines in the file that change the INSTANCE methods, it works. But I need to do it on the "class type" (i.e. prototype).

Any suggestions would be appreciated.

Thanks, Guypo

Here's the file I created

<html><body>
<img id="testImg" src=".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");
// Unmenting 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>

I'm trying to override the Element object's addEventListener method, in a cross-browser manner. The purpose is so that I can load some 3rd party scripts asynchronously, and those scripts call this method prematurely.

I created an HTML file that works perfectly in Chrome, but on Firefox I get this exception:

"Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)"

If you ment out the lines in the file that change the INSTANCE methods, it works. But I need to do it on the "class type" (i.e. prototype).

Any suggestions would be appreciated.

Thanks, Guypo

Here's the file I created

<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");
// Unmenting 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>
Share Improve this question edited Jan 24, 2011 at 22:33 Marcel Korpel 21.8k6 gold badges62 silver badges80 bronze badges asked Jan 24, 2011 at 22:00 GuypoGuypo 2173 silver badges5 bronze badges 2
  • I think element prototyping isn't cross-patible, I would suggest using jQuery or some framework. – JCOC611 Commented Jan 24, 2011 at 22:27
  • 2 I agree, but I can't modify the 3rd party scripts I'm using, so my only option is to change the JavaScript environment they run in by changing the prototype – Guypo Commented Jan 24, 2011 at 22:58
Add a ment  | 

2 Answers 2

Reset to default 6

Like Marcel says, this has to do with the way host objects are exposed. The problem is that if you override a predefined property of an interface, it doesn't get changed in the interfaces that inherit from it (at least in Firefox).

Although I agree with Marcel's remarks, there is in fact a way to do this. You should override the property of the lowest possible interface of the object you want to do this for. In your case this would be the HTMLImageElement.

This will do the trick:

(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. Please use a valid Doctype, preferably one that cast browsers into (Almost) Standards mode (<!DOCTYPE html> is fine).

  2. typeof is an operator, you don't need the parentheses (but it doesn't hurt)

  3. Most important: don't try to manipulate DOM Element's prototype: those are host objects and you can't rely on host objects exposing any of the core JavaScript functionality of an object. Worse, there may be a performance penalty and you might break other things. Stay away from that technique. For more information, read What’s wrong with extending the DOM.

What is it that you want to achieve, that you want your event listeners to be called automatically when using 3rd party scripts?

发布评论

评论列表(0)

  1. 暂无评论