我很好奇内联元素属性事件的内容如何在后台运行。
我们从一个简单的功能开始
function handler(e) {
console.log(e);
}
用例1
如果我们想将此处理程序添加到按钮中,我们可以这样做:
<button onclick="handler();">Click Me</button>
登录时点击:undefined
足够好,我们在不传递参数的情况下调用了函数。
用例2
如果我们现在更改按钮以将event
作为参数:
<button onclick="handler(event);">Click Me</button>
我们登录点击:MouseEvent{ ... }
现在,我们可以记录事件了,
用例3
但是如果我们仅指定函数名称怎么办?
<button onclick="handler">Click Me</button>
什么都没发生!,我希望仅引用一个函数就能解决问题。因此,当发生“ onlick”事件时,将使用适当的事件参数来调用所引用的函数。
用例4
当我们在javascript中添加处理程序时:
const btn = document.getElementById('btn');
btn.onclick = handler;
它起作用,捕获事件并记录相关的event
对象。
结论性问题
无论我们直接传递给onclick=""
的任何文本/内容/声明,它基本上都在其上运行eval()
吗?然后,当我们将其附加到javascript(btn.onclick = ...
)中时,它会经过适当的过程来拦截事件,然后调用有界处理程序函数并将其传递给相应的事件对象(例如MouseEvent
)?
快速笔记
明确地说,这是一个翔实的问题,可以了解基本原理,而忽略这是不好还是好的做法。目前尚未讨论。
答案 0 :(得分:2)
是的,在内联处理程序中,属性文本实际上只是eval
格式,带有一些限定条件。什么
<button onclick="handler">Click Me</button>
大致等于如果您有一个(true)处理程序,该处理程序引用了 handler
函数但未调用它,例如:
btn.onclick = () => {
handler;
};
这不会引发错误(因为handler
是可引用的),但是也不会运行handler
,因为您只引用该函数,而不调用它。
这样做的时候
btn.onclick = handler;
您正在将引用传递给handler
内部onclick
内部,然后在单击按钮时稍后调用该引用。
(如果您完成了btn.onclick = handler;
,handler
将被立即调用,并且它的返回值将被添加为侦听器,这不是您想要的。想要)
这样做的时候
<button onclick="handler(event);">Click Me</button>
您要传递的event
自变量来自window.event
,这就是可引用的原因。
就像我说的那样,有一些限定条件:内联处理程序在运行的整个文本中隐式使用with(this)
之类的内容,其中this
是有问题的元素。 (如Quentin's answer所示,它还对with
使用document
并包含表单)For example:
<a onclick="search();">Click me!</div>
在解释器中看起来像:
<a onclick="
with(this) {
search();
}
">Click me!</div>
这是有问题的,因为search
是HTMLAnchorElement.prototype
的属性。如果这些变量名是元素原型链上任何位置的属性,则引用其他变量名也可能会遇到类似的问题。
最好完全避免使用内联处理程序,而应使用Javascript正确附加事件。
答案 1 :(得分:2)
这不会发生,但您可以这样想象:
想象一下,javascript引擎将onclick
属性的内容另存为字符串,并且当用户单击该元素然后对其内容进行求值。
例如:
function foo(a, b) {
alert(a + ' ' + b);
}
<button onclick="foo('hello', 'world')">click me</button>
<button onclick="(function () { alert ('I\'m an inline IIFE') })()">click me</button>
与eval("foo('hello', 'world')"
相同。如果您通过event
或this
或其他关键字怎么办?
好吧,同样在这里,您可以想象一个javascript引擎会这样做:
var this = /* create context */;
var event = /* create event */;
eval("foo(this, event)");
这就是规范所说的,需要评估属性!我并不是说引擎使用eval
:P
示例:
<button onclick="alert('hello world')">Click me</button>
btn.onclick = handler;
呢?
这是另一双鞋。 onclick
属性是一个回调,它需要一个函数引用。
答案 2 :(得分:1)
将HTML属性用于事件时,实际上是在幕后创建了一个函数,该函数被分配为相关事件的处理程序。
event
参数作为参数另请参阅How HTML attribute for event handlers are working under the hood
所以
在情况1中,生成的处理程序:
function handlerHtml(event) {
handler()
}
在情况2中,生成的处理程序:
function handlerHtml(event) {
handler(event)
}
在情况3中,生成的处理程序:
function handlerHtml(event) {
handler
}