Below is my code and it doesn't work. After I rename the "click()" to "click1()" it works, why?
<html>
<head>
<title></title>
<script type="text/javascript">
function click() {
document.getElementById("content").innerHTML = "abc";
}
</script>
</head>
<body>
<button onclick="click()">try it</button><br />
<div id="content"></div>
</body>
</html>
Below is my code and it doesn't work. After I rename the "click()" to "click1()" it works, why?
<html>
<head>
<title></title>
<script type="text/javascript">
function click() {
document.getElementById("content").innerHTML = "abc";
}
</script>
</head>
<body>
<button onclick="click()">try it</button><br />
<div id="content"></div>
</body>
</html>
Share
Improve this question
edited Dec 8, 2010 at 15:44
Andy E
345k86 gold badges480 silver badges450 bronze badges
asked Dec 8, 2010 at 14:16
micahli123micahli123
4801 gold badge7 silver badges10 bronze badges
2
- Also note that changing the "onclick" to "window.click()" makes it work – Pointy Commented Dec 8, 2010 at 14:47
- Thank you all. I'm a beginner. I think I have to speed up my learning at w3school. It's my first post on stackoverflow.. I'm so happy it's very active and kind here. To Pointy: I will try window.click() after I learn more.. – micahli123 Commented Dec 8, 2010 at 15:12
7 Answers
Reset to default 17The string values of "onfoo" handler attributes are interpreted as the bodies of handler functions. In other words, it's as if the string value of the attribute is passed to new Function("event", str)
with the result being the handler function used.
Additionally, the lexical scope of the function is established as follows, taken from the HTML5 spec (which I consult only in its capacity of a prehensive description of browser behavior):
Lexical Environment Scope
* Let Scope be the result of NewObjectEnvironment(the element's Document, the global environment).
* If the element has a form owner, let Scope be the result of NewObjectEnvironment(the element's form owner, Scope).
* Let Scope be the result of NewObjectEnvironment(the element's object, Scope).
Thus it's as if there are up to two nested with
blocks implicitly wrapped around the code. Thus in this case the effect is that of calling this:
var handler = new Function("event", "with (this) { click(); }");
Because there's a "click" method on the DOM element corresponding to the <button>
, that function is what's called by the handler, not the global one established by the script tag. If the "onclick" attribute is set to "window.click();" then the page works properly.
There's already a function called click, responsible for calling the event handler. By declaring another, you override the first, so the event doesn't work anymore.
See the answer by Pointy for why this happens.
To avoid the issue, there are several options. Since the problem is that a function name will classh with a property name, all revolve around unambiguously referring to the function needed.
Use .addEventListener()
(Remended)
This is the most straight forward and conflict free way to register event handlers using JavaScript.
NOTE: If the <script>
tag is in the <headd>
section or otherwise before the element that is looked up, then the JavaScript code will execute before the element is in the DOM and thus will not be found. See Why does jQuery or a DOM method such as getElementById not find the element? for more information and ways to avoid that. The two easiest ones are moving the <script>
section at the end of the body or using defer
(when the <script>
tag uses the src
attribute).
Here is a solution where the <script>
tag is moved:
<html>
<head>
<title></title>
</head>
<body>
<button>try it</button><br />
<div id="content"></div>
<script type="text/javascript">
function click() {
document.getElementById("content").innerHTML = "abc";
}
document.querySelector("button")
.addEventListener("click", () => click());
</script>
</body>
</html>
Use window.yourFunction
This will unambiguously refer to what is is defined in the global scope:
<html>
<head>
<title></title>
<script type="text/javascript">
function click() {
document.getElementById("content").innerHTML = "abc";
}
</script>
</head>
<body>
<button onclick="window.click()">try it</button><br />
<div id="content"></div>
</body>
</html>
Drawbacks
One drawback is that there can still be clashes with the same name. This time with something defined in window
.
Another drawback is that all other code can also use the global scope, the function might be accidentally overwritten.
Essentially, this solution is only one step removed from the original problem of the name of a function clashing with another name but still vulnerable to the same form of clash.
Rename the function
This will disambiguate the function by making it distinct
<html>
<head>
<title></title>
<script type="text/javascript">
function myClick() {
document.getElementById("content").innerHTML = "abc";
}
</script>
</head>
<body>
<button onclick="myClick()">try it</button><br />
<div id="content"></div>
</body>
</html>
Drawbacks
The new name can still clash with something. If not with a DOM property, then with something from window
. And if not now then perhaps later in the future when:
- a new property is added to HTML
- this could even be by somebody defining a custom attribute or custom element
- a new property is added to
window
- again, this could be another script on the page adding it
Essentially, this has a chance to merely delay the problem.
click() is the inbuilt of javascript's button object.
click() a reserved name for a method used in HTML5 http://www.w3/TR/html5/webappapis.html
click is predefined event. You should not use predefined events.
You should perhaps consider using jQuery to refactor your code:
<html>
<head>
<title></title>
</head>
<body>
<button id="button1">try it</button><br />
<div id="content"></div>
<script type="text/javascript" src="https://ajax.googleapis./ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#button1").click(function() {
$("#content").html("abc");
});
});
</script>
</body>
</html>