请教大家,一个我偶然发现的关于 JS 事件处理的小问题

2019-04-21 18:55:33 +08:00
 kuanng

我给 div 绑定一个 click 事件,代码如下:

<div onclick="click()"></div>

<script>
  function click() {
    console.log('click')
  }
</script>

单击触发 click 事件,运行结果如下:

我发现控制台没有任何的输出,第一时间我检查了一下代码,看上去好像没有任何问题呀。

突然想到, [难道 handle 函数的名字不能为 click ?] 我试着修改为 myclick,修改后代码如下:

<div onclick="myclick()"></div>

<script>
  function myclick() {
    console.log('click')
  }
</script>

重新运行,结果如下:

居然真的可以,难道 handle 函数名不可以和事件名相同? js 中还有这样的规定? [心想,我 js 基础太差了吧]

我开始实验其他事件是不是也有相同的规定,所以我将 click 事件修改为 dblclick 事件,代码如下:

<div ondblclick="dblclick()"></div>

<script>
  function dblclick() {
    console.log('dblclick')
  }
</script>

双击触发事件,结果如下:

居然可以 log 出来? [不是说好的 handle 函数名不能和事件名相同么?] 什么情况???

接下来我测试了 mousedown, mouseup, keyup, keydown, keypress 事件,都可以 log 出来,这就不上图了。

凭直觉, [应该只有 click 事件处理函数名不能为 click ] ,但这是为什么呢?

我加断点调试再次确定了没有执行 script 中的 click 处理函数。

我分析名为 click 的事件处理函数没有被调用的原因,难道是被覆盖了?

如果是这样的话,那么我应该可以 console.log(click) ,代码如下:

<div onclick="console.log(click)"></div>

运行结果如下:

显而易见这样写是不可以的:

<div onclick="myclick()"></div>

<script>
  function myclick() {
    console.log(click)  //ReferenceError: click is not defined
  }
</script>

[果然是本地函数 click 覆盖了名为 click 的处理函数] ,但是随意想想,什么情况?有全局 click 函数???

下面就是让我感到不解的地方。

<div onclick="console.log('click'); click()"></div>

运行结果如下:

难道执行了两次 onclick 中的代码?

试着再调用一次 click(),代码如下:

<div onclick="console.log('click'); click(); click()"></div>

看出来了规律:

但是怎么解释这个运行结果?这也没有递归啊,js 引擎是怎么执行这段代码的?

希望大家可以解决这个问题!

环境:win10 + chrome

1924 次点击
所在节点    程序员
12 条回复
rabbbit
2019-04-21 19:12:36 +08:00
<div onclick="console.log(this.click === click);console.log(event.currentTarget.click === click)"></div>
Mutoo
2019-04-21 19:15:35 +08:00
我之前遇到过 <form onsubmit="submit()"></form> 也遇到类似的问题。

在 onclick 这个 DOM Level 0 的事件侦听器上,存在一个默认的 With Block 作用域指向元素本身(这里的 this 即 div ),于是这里的 click 方法指向的是 div.click() (优先级更高)而不是 window.click()

如果你用 DOM Level 3 的事件侦听器:div.addEventListener('click', ...) 则不会有这个问题。
ayase252
2019-04-21 19:27:18 +08:00
Biwood
2019-04-21 19:34:28 +08:00
当使用 attribute 来绑定事件时,handler 的 this 指向元素本身,也就是 div 元素,所以 click()也相当于 div.click()。
为什么其他事件名不行?因为 div 是由 HTMLDivElement 接口实现的,而它又继承自 HTMLElement,click 属于该接口的一个 method,而 dblclick 则不是。
请参考 https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement#Methods
kuanng
2019-04-21 19:58:45 +08:00
@Biwood 学到了,感谢!
kuanng
2019-04-21 20:01:06 +08:00
@Biwood 请问第二个问题的代码为什么不以递归的方式一直执行?
Biwood
2019-04-21 20:13:06 +08:00
@kuanng 浏览器的安全策略,第二轮递归中的 div.click 不是由人类行为直接触发,会被浏览器阻止。
kuanng
2019-04-21 22:33:00 +08:00
感谢大家的回复!
meepo3927
2019-04-22 11:23:23 +08:00
很涨姿势
buhi
2019-04-22 11:32:05 +08:00
很偏门的姿势呢 学习了
longjiahui
2019-04-22 13:59:23 +08:00
完全没试过直接用 click 命名的。 🧱
zhw2590582
2019-04-22 14:37:11 +08:00
涨姿势了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/557274

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX