13

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>
Andy E
  • 338,112
  • 86
  • 474
  • 445
micahli123
  • 460
  • 1
  • 7
  • 10
  • Also note that changing the "onclick" to "window.click()" makes it work – Pointy Dec 08 '10 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.com. I'm so happy it's very active and kind here. To Pointy: I will try window.click() after I learn more.. – micahli123 Dec 08 '10 at 15:12

7 Answers7

17

The 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 comprehensive 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.

Pointy
  • 405,095
  • 59
  • 585
  • 614
1

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.

travelboy
  • 2,647
  • 3
  • 27
  • 37
  • Where is this "click" function? Why is it in lexical scope when the string value of the "onclick" attribute is (effectively) given to `eval()` by the browser? – Pointy Dec 08 '10 at 15:03
  • @Pointy: It's a function of the element. – thejh Dec 08 '10 at 15:11
  • Yes thanks - the answer can be found in the HTML 5 spec, and probably elsewhere. The text of the "onclick" attribute is interpreted as a function body, but with the added twist of an implicit `with` block referring to the element. If it were in a `
    `, then that too would get an implicit `with` block.
    – Pointy Dec 08 '10 at 15:30
  • This helped me. I had a function called "export()" that I couldn't get to fire. I was going down a rabbit hole looking for problems until figuring out that the name of the method was the problem. Thanks! – Kirk Liemohn Jun 12 '12 at 19:26
0

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() (Recommended)

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.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
-1

click() is the inbuilt of javascript's button object.

Madhur Ahuja
  • 22,211
  • 14
  • 71
  • 124
-3

click() a reserved name for a method used in HTML5 http://www.w3.org/TR/html5/webappapis.html

sreimer
  • 4,913
  • 2
  • 33
  • 43
-3

click is predefined event. You should not use predefined events.

sreekanth
  • 709
  • 2
  • 9
  • 20
-3

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.com/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>
GateKiller
  • 74,180
  • 73
  • 171
  • 204
  • 2
    Thank you for your tutorial. I think I have to learn jQuery as I have already learned some javascript. Thank you for your instruction in using the jQuery file in google server other than my server. – micahli123 Dec 09 '10 at 07:00