内联onclick如何评估?

时间:2019-05-23 08:30:59

标签: javascript html

我很好奇内联元素属性事件的内容如何在后台运行。

我们从一个简单的功能开始

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)?

快速笔记

明确地说,这是一个翔实的问题,可以了解基本原理,而忽略这是不好还是好的做法。目前尚未讨论。

3 个答案:

答案 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>

这是有问题的,因为searchHTMLAnchorElement.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')"相同。如果您通过eventthis或其他关键字怎么办?

好吧,同样在这里,您可以想象一个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属性用于事件时,实际上是在幕后创建了一个函数,该函数被分配为相关事件的处理程序。

  • 函数的主体是属性的内容。应该是JavaScript代码。
  • 该函数将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
}