addEventListener 与 attachEvent 区别

比较两种事件绑定方法的语法、this 指向和事件流差异

问题

addEventListenerattachEvent 有什么区别?

解答

addEventListener 是 W3C 标准方法,attachEvent 是 IE8 及以下的专有方法。

语法对比

// addEventListener (标准方法)
element.addEventListener('click', handler, false);

// attachEvent (IE8 及以下)
element.attachEvent('onclick', handler);

主要区别

// 1. 事件名写法不同
element.addEventListener('click', fn);    // 不带 'on'
element.attachEvent('onclick', fn);       // 必须带 'on'

// 2. this 指向不同
element.addEventListener('click', function() {
  console.log(this);  // 指向 element
});

element.attachEvent('onclick', function() {
  console.log(this);  // 指向 window
});

// 3. 事件流支持不同
// addEventListener 第三个参数控制捕获/冒泡
element.addEventListener('click', fn, true);   // 捕获阶段
element.addEventListener('click', fn, false);  // 冒泡阶段

// attachEvent 只支持冒泡,没有第三个参数
element.attachEvent('onclick', fn);

兼容性封装

function bindEvent(element, type, handler) {
  if (element.addEventListener) {
    // 标准浏览器
    element.addEventListener(type, handler, false);
  } else if (element.attachEvent) {
    // IE8 及以下
    element.attachEvent('on' + type, function() {
      // 修正 this 指向
      handler.call(element);
    });
  } else {
    // 兜底方案
    element['on' + type] = handler;
  }
}

// 使用
bindEvent(document.getElementById('btn'), 'click', function() {
  console.log(this);  // 始终指向绑定的元素
});

移除事件

// addEventListener 对应 removeEventListener
element.removeEventListener('click', handler, false);

// attachEvent 对应 detachEvent
element.detachEvent('onclick', handler);

关键点

  • addEventListener 是标准方法,attachEvent 是 IE8 及以下专有
  • 事件名:addEventListener 不带 onattachEvent 必须带 on
  • this 指向:addEventListener 指向元素,attachEvent 指向 window
  • addEventListener 支持捕获和冒泡,attachEvent 只支持冒泡
  • 现代开发中 attachEvent 已基本不需要考虑