4

问题

今天突然要维护一个老古董的项目,里面大部分都是原生js和jquery,用vue之类多了,这些都有些生疏... 代码中有一个HTML事件处理程序,<button onclick="clickHandler(e)">屠龙宝刀点击就送</button>

function clickHandler(e) {
  console.log(e.target);
}

刚开始都没注意有啥错,然后在函数中e.target等都会报错:ReferenceError: e is not defined

很明显,传入的事件对象参数是错误的,在HTML事件处理程序的情况下正确的做法是传入完整的event名称,<button onclick="clickHandler(event)">屠龙宝刀点击就送</button>

其实event可以看作是window.event的简写,用window对象的其他属性试验下就可以发现,比如用location<button onclick="clickHandler(location)">屠龙宝刀点击就送</button>, 那么函数中e.href即可打印出当前链接。

function clickHandler(e) {
  console.log(e.href);
}

思考

其实上面本来不是个问题,主要平时很少用行内的HTML事件处理程序,所以随手把参数event写错为了e。在DOM0和DOM2级事件处理程序中,浏览器都会将一个event对象传入到事件处理程序中,这种用js指定的事件处理程序的形参当然可以随便命名了,一般简写为e了。

DOM0

仍然用上面的声明函数:

function clickHandler(e) {
  console.log(e.target);
}
document.getElementsByTagName('button')[0].onclick = clickHandler;

准确的打印出了button元素。

其实还可以将事件处理函数定义为无参函数,可以用arguments来获取事件对象。

function clickHandler1() { //无参处理函数
  var e = arguments[0];
  console.log(e.target);
}

DOM2

最常用的就是dom2级事件处理程序了:

document.getElementsByTagName('button')[0].addEventListener('click', clickHandler, false );

同样也可以使用无参函数

document.getElementsByTagName('button')[0].addEventListener('click', clickHandler1, false );

匿名函数时候需要注意的

DOM1和2级事件处理程序也常用匿名函数的方式:

document.getElementsByTagName('button')[0].onclick = (e) => {
  console.log(e.target);
}

这样传入event参数的有参匿名函数是没有问题的,但是如果用无参函数的话下面代码就会报错出问题:

document.getElementsByTagName('button')[0].onclick = () => {
  var e = arguments[0];
  console.log(e.target);
}

根据MDN上描述,arguments不能使用箭头函数,因为箭头函数没有自己的this,使用的是封闭执行作用域的this。
但是若非要使用arguments的话可以传入...args:

document.getElementsByTagName('button')[0].onclick = (...args) => {
  var e = args[0];
  console.log(e.target);
}

事件处理程序传递多个参数

在最早的HTML事件处理程序中我们可以直接传入多个参数,

<button onclick="clickHandler(event, 'a', 'b')">屠龙宝刀点击就送</button>

但是DOM0和2级事件处理程序默认只传入event参数,可以采用闭包的方法(IIFE)来处理:

document.getElementsByTagName('button')[0].addEventListener('click', (function(a, b) {
    return function(e) {clickHandler(e, a, b); };
}) ('a', 'b'), false);

event.targetevent.currentTarget

既然都写了事件处理程序顺便再复习下这两个的区别,target是事件的实际目标,currentTarget是处理事件的元素,也就是绑定事件函数的元素,事件处理函数中this的值等于currentTarget

在线演示

在线demo

参考资料


Alee
291 声望8 粉丝

既然路走偏了,那就重新开始吧。