请考虑以下代码。
<!DOCTYPE html>
<title>Question</title>
<script>
function report(handler, _this) {
alert(
"handler:\n" + handler + "\n" +
"this: " + _this + "\n" +
"event: " + event + "\n"
)
}
</script>
<input type=button id=A value=A onclick="report(A.onclick, this)">
<script>function f() {report(B.onclick, this)}</script>
<input type=button id=B value=B onclick="f()">
<input type=button id=C value=C>
<script>C.onclick = function () {report(C.onclick, this)}</script>
通过点击按钮,我看到:
A.onclick
和B.onclick
被 Package 在“function onclick(event){...}”中。
1.在B.onclick
中,this
是窗口(而不是按钮)。
是否有其他考虑?
4条答案
按热度按时间6ie5vjzr1#
内联侦听器没有任何好处,相反,它是一种非常有缺陷的向HTML元素添加事件侦听器的方法。
执行差异
#1
this
属性代码中的值绑定到JavaScriptwith
的元素。在内联代码中,函数(或任何全局变量)首先从元素中搜索。如果找不到(通常是这种情况),内联侦听器将从元素的原型链中搜索该函数。如果没有找到匹配的属性名,搜索将到达window
,并运行调用的全局函数。但如果函数名与查找路径上的任何属性名冲突,则会引发错误,或者执行意外的函数。内联侦听器如何找到 Package 表单的
action
属性的示例,只需单击输入:#2属性代码的返回值实际上用于特定事件(如
onsubmit
)。返回false
将阻止事件的默认操作。来自附加了addEventListener
的侦听器的返回值总是被完全忽略(该值没有接收者)。#3处理程序中使用的所有变量和函数必须是全局可访问的。这也算是一个破绽。
经常被误解的行为
在属性代码中调用的函数不是实际的事件处理程序函数,属性本身中的代码是附加的处理程序。因此,事件对象和正确的
this
值仅存在于属性处理程序代码中。如果在全局函数中需要这些值中的任何一个,则必须在调用全局函数时手动传递它们。这是任何JavaScript代码的正常行为,在
addEventListener
附带的事件处理程序中也是如此。如果你从一个事件处理程序调用另一个函数,你必须传递事件对象,并绑定/传递this
值,如果其他函数需要这些值。从事件侦听器调用另一个函数的示例。
正如我们所看到的,在附加类型之间,事件对象和
this
值的处理方式没有区别。当事件触发时,在内联侦听器中,属性中的代码是第一个执行的代码,而对于其他附加类型,第一个执行的代码是处理程序函数本身。(示例中的事件对象部分是不相关的,因为几乎所有浏览器当前都实现了全局事件对象。global event object目前已弃用(2023年),因此这将是未来的一个问题。inline listener中的缺陷
#1一个元素只能附加一个同类型的监听器。
#2内联监听器是潜在的攻击载体,因为属性中的监听器代码和从属性代码调用的任何函数都很容易被DevTools覆盖。
#3当编写内联侦听器时,正确引用字符串是复杂的。在服务器上编写动态标记时,引用的复杂性会增加,因为您必须处理HTML引用,JS引用和服务器端语言引用。
#4内联监听器不能在模块和浏览器扩展中工作(这些环境不在全局命名空间中,并且您不能从内联监听器调用模块或插件代码中编写的函数),并且不被许多框架接受,并且它们不会通过任何安全审计。
#5内联侦听器通过混合页面的表示层和操作层来打破Separation of concerns原则。
element.onxxxx
onxxxx
属性没有缺陷#3,#4和#5,但是你不能用onxxxx
属性添加一个以上的监听器,而且因为元素是全局的,所以监听器很容易用DevTools覆盖。addEventListener
结论如下:使用
addEventListener
将事件附加到HTML元素,它没有任何缺陷。this
被正确绑定,事件对象被正确传递,可以附加多个相同类型的事件,并且没有安全风险(当处理程序不是全局可访问的函数时),因为一切都发生在封装的代码中,而不需要单个全局变量或函数。作为奖励,您可以选择触发事件的阶段,将仅触发一次的事件附加到元素而无需额外的工作,并获得更好的滚动某些事件的性能。
ctehm74n2#
当从on-event处理程序调用代码时,它的
this
被设置为放置侦听器的DOM元素:但是请注意,只有外部代码才以这种方式设置this。在这种情况下,内部函数的
this
没有设置,所以它返回全局/窗口对象(即non–strict
模式中的默认对象,其中调用未设置this
)。在全局上下文和函数上下文中检查
this
。另一个考虑因素是当您使用
addEventListener
时。检查带有匿名函数和箭头函数的事件侦听器,并在箭头函数中使用
this
。请注意,虽然anonymous和arrow函数类似,但它们具有不同的
this
绑定。虽然anonymous(以及所有传统的JavaScript函数)创建自己的this绑定,但箭头函数继承了包含上下文的this绑定。这里有一篇我写的关于JavaScript
this
keyword的简单文章,但它没有提到事件处理程序。lnvxswe23#
还有另一个考虑。考虑以下代码。
f
在onclick中未定义,因为值为1的按钮(因为f
是在模块中定义的)。因此,当事件处理程序必须执行模块中的代码(例如,使用import
的代码)时,必须在模块中分配事件处理程序。xghobddn4#
在HTML中设置事件侦听器没有什么特别的好处。此外,它被认为是有害的,例如CSP禁止它https://developers.google.com/web/fundamentals/security/csp#inline_code_is_considered_harmful