对于IE系列、Chrome和Safari,都可以使用简单的on[事件名] in window检测事件是否存在,因此原有的提供防止DOM污染后的hasEvent函数可以很好地完成任务。
唯有Firefox上,以下代码会给出错误的结果:
alert(‘onload’ in window); //Firefox弹出false
alert(‘onunload’ in window); //Firefox弹出false
alert(‘onerror’ in window); //Firefox弹出false值得庆幸也值得愤怒的是,Firefox很诡异地可以在div等元素上检测到以上3个事件,这直接导致对普通DOM元素检测事件的错误,也导致我们可以检测到window上的事件。好在一般开发者也不会去一个div之类的元素上检测是否有unload事件。因此补充hasEvent函数,将window上的事件导向一个div对象来检测部分事件:
if (!supported) {
if (!element.setAttribute || !element.removeAttribute) {
element = document.createElement(‘div’);
}
element.setAttribute(name, ‘return;’);
supported = typeof element[name] == ‘function’;
element.removeAttribute(name);
}至此,一个较为完整的hasEvent函数完成了,虽然在Firefox上还存在一些问题,比如以下的代码:
alert(hasEvent(‘unload’, document.createElement(‘div’)); //Firefox弹出true但是在99%的应用场合之下,这个函数是可以正确的工作的。
添加缓存
为了进一步提高hasEvent的工作效率,考虑到DOM规范规定的事件数量不多,可以对通用的事件(即不指定检测的元素对象)检测添加缓存机制。
添加了缓存之后,最终完整的hasEvent函数如下:
var hasEvent = (function () {
var tags = {
onsubmit: ‘form’, onreset: ‘form’,
onselect: ‘input’, onchange: ‘input’,
onerror: ‘img’, onload: ‘img’, onabort: ‘img’
},
cache = {}; return function(name, element) {
name = name.indexOf(‘on’) ? ‘on’ + name : name;
//命中缓存
if (!element && name in cache) {
return cache[name];
}
element = element || document.createElement(tags[name] || ‘div’);
var proto = element.__proto__ || {},
supported = name in element,
temp;
//处理显示在元素的__proto__上加属性的情况
if (supported && (temp = proto[name]) && delete proto[name]) {
supported = name in element;
proto[name] = temp;
}
//处理Firefox不给力的情况
//Firefox下’onunload’ in window是false,但是div有unload事件(OTL)
if (!supported) {
if (!element.setAttribute || !element.removeAttribute) {
element = document.createElement(‘div’);
}
element.setAttribute(name, ‘return;’);










