I have heard many times that using JavaScript events, such as onClick()
, in HTML is a bad practice, because it\'s not good for semantics. I would like to know w
Two more reasons not to use inline handlers:
Given an arbitrary string, if you want to be able to construct an inline handler that calls a function with that string, for the general solution, you'll have to escape the attribute delimiters (with the associated HTML entity), and you'll have to escape the delimiter used for the string inside the attribute, like the following:
const str = prompt('What string to display on click?', 'foo\'"bar');
const escapedStr = str
// since the attribute value is going to be using " delimiters,
// replace "s with their corresponding HTML entity:
.replace(/"/g, '"')
// since the string literal inside the attribute is going to delimited with 's,
// escape 's:
.replace(/'/g, "\\'");
document.body.insertAdjacentHTML(
'beforeend',
'<button onclick="alert(\'' + escapedStr + '\')">click</button>'
);
That's incredibly ugly. From the above example, if you didn't replace the '
s, a SyntaxError would result, because alert('foo'"bar')
is not valid syntax. If you didn't replace the "
s, then the browser would interpret it as an end to the onclick
attribute (delimited with "
s above), which would also be incorrect.
If one habitually uses inline handlers, one would have to make sure to remember do something similar to the above (and do it right) every time, which is tedious and hard to understand at a glance. Better to avoid inline handlers entirely so that the arbitrary string can be used in a simple closure:
const str = prompt('What string to display on click?', 'foo\'"bar');
const button = document.body.appendChild(document.createElement('button'));
button.textContent = 'click';
button.onclick = () => alert(str);
Isn't that so much nicer?
What do you think the following code will log?
let disabled = true;
<form>
<button onclick="console.log(disabled);">click</button>
</form>
Try it, run the snippet. It's probably not what you were expecting. Why does it produce what it does? Because inline handlers run inside with
blocks. The above code is inside three with
blocks: one for the document
, one for the <form>
, and one for the <button>
:
let disabled = true;
<form>
<button onclick="console.log(disabled);">click</button>
</form>
Since disabled
is a property of the button, referencing disabled
inside the inline handler refers to the button's property, not the outer disabled
variable. This is quite counter-intuitive. with
has many problems: it can be the source of confusing bugs and significantly slows down code. It isn't even permitted at all in strict mode. But with inline handlers, you're forced to run the code through with
s - and not just through one with
, but through multiple nested with
s. It's crazy.
with
should never be used in code. Because inline handlers implicitly require with
along with all its confusing behavior, inline handlers should be avoided as well.
With very large JavaScript applications, programmers are using more encapsulation of code to avoid polluting the global scope. And to make a function available to the onClick action in an HTML element, it has to be in the global scope.
You may have seen JS files that look like this...
(function(){
...[some code]
}());
These are Immediately Invoked Function Expressions (IIFEs) and any function declared within them will only exist within their internal scope.
If you declare function doSomething(){}
within an IIFE, then make doSomething()
an element's onClick action in your HTML page, you'll get an error.
If, on the other hand, you create an eventListener for that element within that IIFE and call doSomething()
when the listener detects a click event, you're good because the listener and doSomething()
share the IIFE's scope.
For little web apps with a minimal amount of code, it doesn't matter. But if you aspire to write large, maintainable codebases, onclick=""
is a habit that you should work to avoid.
It's not good for several reasons:
eval
The simplest thing would be to add a name
attribute to your <a>
element, then you could do:
document.myelement.onclick = function() {
window.popup('/map/', 300, 300, 'map');
return false;
};
although modern best practise would be to use an id
instead of a name, and use addEventListener()
instead of using onclick
since that allows you to bind multiple functions to a single event.
There are a few reasons:
I find it aids maintenence to separate markup, i.e. the HTML and client-side scripts. For example, jQuery makes it easy to add event handlers programatically.
The example you give would be broken in any user agent that doesn't support javascript, or has javascript turned off. The concept of progressive enhancement would encourage a simple hyperlink to /map/
for user agents without javascript, then adding a click handler prgramatically for user agents that support javascript.
For example:
Markup:
<a id="example" href="/map/">link</a>
Javascript:
$(document).ready(function(){
$("#example").click(function(){
popup('/map/', 300, 300, 'map');
return false;
});
})