内联Javascript(以HTML格式)如何工作?


129

我知道这是不好的做法。尽可能不要编写这样的代码。

当然,我们总是会发现自己的内联Javascript代码段可以快速解决问题。

我追求此查询的目的是充分了解编写类似以下内容时会发生什么(以及潜在的陷阱):

<a href="#" onclick="alert('Hi')">Click Me</a>

据我所知,这在功能上与

<script type="text/javascript">
   $(function(){ // I use jQuery in this example
       document.getElementById('click_me').onclick = 
           function () { alert('Hi'); };
   });
</script>
<a href="#" id="click_me">Click Me</a>

由此推断,似乎已将分配给属性的字符串onclick插入到一个匿名函数中,该匿名函数已分配给元素的单击处理程序。确实是这样吗?

因为我开始做这样的事情:

<a href="#" onclick="$(this).next().fadeIn(); return false;">Display my next sibling</a> <!-- Return false in handler so as not to scroll to top of page! --> 

哪个有效。但是我不知道这是多少黑客。它看起来很可疑,因为没有明显的函数要从中返回!

您可能会问,为什么要这样做,史蒂夫?内联JS是不好的做法!

老实说,我只是为了修改页面的一个部分而厌倦了编辑代码的三个不同部分,尤其是当我只是对某个东西进行原型设计以查看它是否可以工作时。在此元素定义与此HTML元素特别相关的代码非常容易,有时甚至很有意义:当我在两分钟后决定这是一个可怕的想法时,我可以对整个div进行核对(或其他任何方法) ),并且在页面的其余部分中没有一堆神秘的JS和CSS碎片,从而使渲染速度稍有降低。这类似于引用局部性的概念,但我们要关注的是错误和代码膨胀,而不是缓存未命中。


3
您是正确的,它是一个匿名函数。
巴林

1
您将需要#click_me在DOMready事件上挂钩查询,或将脚本放在节点之后。
Bergi 2012年

1
在控制台中,执行document.getElementById("click_me").onclick;。或提醒它。您会看到它在一个函数中。
D. Strout,2012年

Answers:


96

您已经接近正确,但尚未考虑this提供给内联代码的值。

<a href="#" onclick="alert(this)">Click Me</a>

实际上更接近:

<a href="#" id="click_me">Click Me</a>
<script type="text/javascript">
document.getElementById('click_me').addEventListener("click", function(event) {
    (function(event) {
        alert(this);
    }).call(document.getElementById('click_me'), event);
});
</script>

内联事件处理程序设置为this等于事件的目标。您还可以在内联脚本中使用匿名函数

<a href="#" onclick="(function(){alert(this);})()">Click Me</a>

7
脚本必须位于标签之后,否则标签在执行时就不存在-我建议更改答案以体现这一点。
undefined 2013年

我如何传播event与内联onclick='myFunction(event)'
老男孩

9

浏览器完成后会做什么

<a onclick="alert('Hi');" ... >

是将“ onclick”的实际值有效地设置为:

new Function("event", "alert('Hi');");

也就是说,它创建了一个期望“事件”参数的函数。(嗯,IE不会;它更像是一个简单的简单匿名函数。)


2
啊。因此,我实际上可以使用该变量从我的内联JS代码片段中event检索事件(以及通过来获取该事件的原始元素event.target)!凉。
史蒂文·卢

1
IE确实不会传递该event参数,但是如果event在此匿名函数中使用IE会将其理解为实际的事件对象。由于匿名函数被设置为windowIE 中对象的属性,因此它将视为window.event
rdleal 2012年

8

事件处理程序属性似乎引发了许多不良做法。错误的做法是不知道并在最合适的地方使用可用的功能。事件属性完全是W3C记录的标准,并且没有不好的做法。这与放置内联样式没有什么不同,内联样式也是W3C记录的,并且有时会很有用。无论您是否将其包装在脚本标签中,都将以相同的方式进行解释。

https://www.w3.org/TR/html5/webappapis.html#event-handler-idl-attributes


2
是的,我倾向于同意,我甚至提供了合理的“理由”,以说明为什么在某些情况下可以合理使用这种内联代码。但是现实是,当某个应用程序(Web应用程序或其他应用程序)变得具有一定的复杂性(并且通常甚至不需要花费很多时间或精力才能达到)时,散布在HTML 布局上的少量代码片段很可能会从可维护性的角度来看,在架构上不健全。例如,通过甚至直接在HTML文件中直接编码JS,人们都在诱使意大利化的滑坡。
史蒂文·卢

1
这是一个正确的,有效的论据,我对此表示赞同。我通常不会自己添加内联脚本或样式。但是人们有不同的口味。例如,许多人喜欢在主体部分添加脚本和样式标签,我无法忍受。但这是有效的,有些人喜欢它。bad practice/spaghettification对某些人来说,缝是good practice/structure对其他人来说。
Daniel B

我一直在查看github.com/styled-components/styled-components,例如,如果将其与react结合使用,我们现在将与您应用程序组件相关联的所有内容都放在一个地方(希望和平地)在一起。实际上,它看起来也不可怕。感觉喜欢进步。因此,将内联样式和代码嵌入HTML是不正确的方法(到目前为止,这似乎是将HTML和样式嵌入JS代码)。
史蒂文·卢

5

回答问题的最佳方法是查看问题。

<a id="test" onclick="alert('test')"> test </a> 

在js中

var test = document.getElementById('test');
console.log( test.onclick ); 

如在中所见console,如果您使用的是chrome,则它会打印带有传入事件对象的匿名函数,尽管在IE中有所不同。

function onclick(event) {
   alert('test')
}

我同意您关于内联事件处理程序的一些观点。是的,它们很容易编写,但我不同意您必须在多个位置更改代码的观点,如果您可以很好地构建代码结构,则无需这样做。


我认为类似的东西<button onclick="login()"> test login </button>非常适合原型制作。您现在要测试需要用户交互的内容,而以后无论如何都将其删除。为什么到处都写额外的代码?
达格·

它不是多余的代码,只是一个额外的匿名函数。它并不仅存在于所有地方,实际上全部位于脚本标记中的一个地方。
阿齐兹·蓬贾尼(Anniz Punjani)2012年

我不确定我们是否具有“结构良好的代码”相同的想法。如果将UI绑定到实际存在核心功能的地方的“核心功能”,那么对我来说,这似乎比将其绑定到UI中更糟糕。我通常将所有UI绑定内容与核心内容分开,并且我感觉OP也可能...
Dagg Nabbit 2012年

3

它看起来很可疑,因为没有明显的函数要从中返回!

这是一个匿名函数,已附加到对象的click事件。

你为什么要这么做,史蒂夫?

你到底为什么做土.....啊,没关系,正如你已经提到的那样,它确实是被广泛采用的坏习惯:)


3

在控制台中尝试:

var div = document.createElement('div');

div.setAttribute('onclick', 'alert(event)');

div.onclick

在Chrome中,它显示如下:

function onclick(event) {
  alert(event)
}

...和非标准name的财产div.onclick就是"onclick"

因此,是否为匿名取决于您对“匿名”的定义。比较类似的内容var foo = new Function(),其中foo.name是一个空字符串,foo.toString()并将产生类似的内容

function anonymous() {

}

这始于对Pointy答案的评论,但实际上并没有作为评论。我认为他的确是最好的答案。
2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.