onclick behaves differently when defined via javascript

Discussion in 'Javascript' started by yawnmoth, Sep 25, 2008.

  1. yawnmoth

    yawnmoth Guest

    yawnmoth, Sep 25, 2008
    #1
    1. Advertisements

  2. Your problem is here:
    <div onclick="test()"> </div>

    It is NOT the same as:
    <div onclick=test> </div>

    The first form runs the "test()" function within the global context. The
    Global Object does not have a property called tagName.


    The second form (as well as your second example) use a function
    reference, and runs within the context of the div.

    Understanding the environment the script runs in is essential to
    understanding what "this" refers to.
     
    Jeremy J Starcher, Sep 26, 2008
    #2
    1. Advertisements

  3. yawnmoth

    Henry Guest

    When an intrinsic event attribute is provided for an element (assuming
    it is recognised, etc.), such as:-

    <div onclick="test()"> </div>

    - the browser uses the string value (the "text()" in this case) as the
    body text of a function that it creates and assigned to the
    corresponding property of the representation of the element in the
    DOM. So what the browser does here is the equivalent of:-

    divRef.onclick = function(event){
    test();
    };

    (with or without the - event - formal parameter, depending on the
    browser)

    The difference between the browser doing this and your doing the
    equivalent of:-

    divRef.onclick = test;

    - is that when the browser calls the function it calls the function as
    - divRef.onclick(); - (with or without an event object as the
    argument, depending on the browser) so the - this - value for the
    execution of the function assigned to - divRef.onclick - is a
    reference to the DIV element, but the function assigned is different.
    One is the function that the browser created (the function that will
    then call - test -) and the other is test itself. In the event that
    the function called is the one created by the browser then when it
    calls - test - it does so in a way that will make the - this - value
    inside that call be a reference to the global object.
     
    Henry, Sep 26, 2008
    #3
  4. yawnmoth

    Jorge Guest

    Correct me if I'm mistaken, but I think I once read somewhere that it
    does an eval() of the text: like (in this case) eval('test()')... ?
     
    Jorge, Sep 26, 2008
    #4
  5. yawnmoth

    Henry Guest

    I cannot tell whether you are mistaken in thinking that you once read
    that somewhere, but it is not the case.
     
    Henry, Sep 26, 2008
    #5
  6. yawnmoth

    yawnmoth Guest

    Why, then, don't any of these work?:

    http://www.frostjedi.com/terra/scripts/demo/this-alert3.html
    http://www.frostjedi.com/terra/scripts/demo/this-alert4.html
    http://www.frostjedi.com/terra/scripts/demo/this-alert5.html

    I can understand the first one. The first one doesn't, presumably,
    work for the same reason that "x=y; y=2;" doesn't result in x equaling
    2 - ie. test hasn't been defined and so onclick is set to undefined.

    But what about the second and third ones? I tried the third one since
    your "It is NOT the same as" didn't include quote marks.
     
    yawnmoth, Sep 26, 2008
    #6
  7. yawnmoth

    Jorge Guest

    :)

    Still, there's something weird here, something that seems to be
    against your theory, see:

    <html>
    <head>
    </head>
    <body onload= "alert((document.body.onload === arguments.callee)+'\r
    \n'+arguments.callee)">
    </body>
    </html>

    how do you explain this ?
     
    Jorge, Sep 26, 2008
    #7
  8. yawnmoth

    Jorge Guest

    The link: http://jorgechamorro.com/cljs/018/
     
    Jorge, Sep 26, 2008
    #8
  9. yawnmoth

    dhtml Guest

    The body tag's onload attribute is really window onload. window has no
    tag, so, somebody (probably in Netscape) once had the idea to make the
    body tag the place to put event handlers from window. Now, event
    handlers for window and body go in the body tag. It is an idea that
    seems to be quite popular, even to this day.

    Ian Hickson has stated that there is a benefit to having window event
    handlers for body attributes and has included at least one new window
    event handler as a body attribute (hashchange). Ian could not comment on
    what that benefit was. I still haven't figured it out...

    The following thread may help explain some more:
    http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2008-September/016184.html

    Your example's title says:
    <title>
    onclick behaves differently when defined via javascript
    </title>

    But the code has:
    <body onload= "alert((document.body.onload ===
    ^^^^^^

    So I think you might got onload mixed up with onclick.

    if you would change:
    <body onload= "alert(window.onload === arguments.callee)">

    Op, FF, Saf (and IE, but I cannot test it).
    'true'

    Or,
    <body onclick= "alert(window.onclick === arguments.callee)">

    FF3
    "true"

    Because of the reasons mentioned in the whatwg thread. In firefox, the
    body content handlers all map to window. I don't see this as being
    invalid behavior, though it's filed as bug in Firefox.

    Also, as mentioned in the whatwg thread, the event handler is really on
    the window. You can trigger the event by clicking outside of the body
    element (give body style="border: 1px solid" to see this in action).

    We can also do one better and see that in firefox, the scope chain is
    not augmented by the body element nor document.

    <body onclick="alert(typeof getElementsByName)" style="border: 1px solid">

    FF3:
    undefined

    Others:
    function (or similar impl dependent string)

    As we saw in an earlier thread, event handler attributes get an aug'd
    scope chain, but this doesn't happen when window "wins" the event
    handler attribute. In Firefox, window "wins" for all mouse events.

    An event that applies to both body and window, the handler goes to window:
    <body onfocus="alert(typeof getElementsByName)" style="border: 1px
    solid" tabindex=1>

    Best to avoid using event handler attributes in body.

    For other elements, event handler attributes have the augmented scope
    chain. To be fair and complete, I should also mention that event
    handlers that reference other identifiers need those identifiers in the
    document first (to avoid reference errors). This often means that
    external script tags have to go in the head, which can slow down page
    load. (Though loading strategy is a bit off-topic here). Regardless,
    there are other ways of registering callbacks.

    Garrett
     
    dhtml, Sep 29, 2008
    #9
  10. yawnmoth

    Henry Guest

    How do I explain what exactly? If you want something explaining it is
    generally a good idea to state what that something is, and given the
    very inconsistent handling of the 'promotion' of BODY element event
    handlers and scope chain augmentation across browsers it would be a
    very good idea to state where you are observing whatever it is you
    want explaining in addition to what it was you observed.
     
    Henry, Sep 29, 2008
    #10
  11. yawnmoth

    Jorge Guest

    Thanks. Wonderful explanation.
    I have updated the link, now it can be seen 'this', 'event.target',
    and where the method has been attached : it certainly a mess, every
    browser does it in a different way.

    http://jorgechamorro.com/cljs/018/
     
    Jorge, Sep 29, 2008
    #11
  12. yawnmoth

    Jorge Guest

    Garret got it perfectly. Never mind. Thanks anyway.
     
    Jorge, Sep 29, 2008
    #12
  13. yawnmoth

    slebetman Guest


    Event assignment API is drastically different between javascript and
    HTML. In HTML it does indeed do an eval of the string text supplied as
    the event handler, because the event handler is supplied as a string:

    <div onclick="alert('hello')"></div>

    BUT, (assuming you care about cross browser compatibility, I'm not
    sure what some weird browser does if you pass it a string in JS), in
    javascript the API is different. It is specified to accept a function
    reference instead of a string. In most browsers the following won't
    work:

    div.onclick = "alert('hello')";

    Again, I'd like to stress that there MAY be a couple of browsers out
    there that will accept the code above, but in general DON'T DO IT.
    Instead, in javascript you must pass it a function:

    function sayHello () {alert('hello')}
    div.onclick = sayHello;

    Which means that if you don't want to declare a function then you must
    wrap your code in an anonymous function.

    div.onclick = function () {
    alert('hello');
    }

    A word of warning. "this" points to different things depending on
    weather you use the HTML API or the javascript API. The HTML API
    magically points "this" to the clicked object while the javascript API
    points it to the global object. Why is this? I don't know. But if I
    were to guess I'd say that the people who created and implemented the
    two different sets of APIs were different people and they have
    different opinions on what is the right thing to do. As is usual in
    software engineering, the standard answer to a "why" question tend to
    be "historical reasons".

    So, to get the clicked element in the javascript API you usually need
    to do someting along the lines of:

    div.onclick = function (evt) {
    // because IE is different:
    evt = evt || window.event;
    // evt now points to the event object

    // because IE is different:
    var target = evt.target || evt.srcElement;
    // target now points to the clicked element
    }
     
    slebetman, Sep 30, 2008
    #13
  14. yawnmoth

    Henry Guest

    <snip>

    This - eval - nonsense needs to be knocked on the head once and for
    all. Browsers do not - eval - the string values of intrinsic event
    attributes, they use them as (all or part of) the bodies of function
    objects that they create internally. This can illustrated by a simple
    example; the attribute:-

    onclick="return false;"

    - is successful, and does what it can be expected to do in whichever
    context it is used in. However, if you attempt:-

    eval("return false;")

    - you will always get an error (a syntax error). For example, IE's
    error dialog reports "'return' statement outside of function".

    Applying - eval - to intrinsic event attribute values would not work,
    so it cannot be what the browser does.
    <snip>

    Bullshit! With the exception of intrinsic event attributes of the BODY
    element (as previously mentioned here) the - this - value in code
    specified as the string value of an intrinsic event attribute is the
    same vale as the - this - value in functions assigned to the
    corresponding intrinsic event properties of DOM elements.

    In javascript the - this - value is determined (only and entirely) by
    how you call a function and the browser calls the functions it created
    from intrinsic event attribute string values and assigned to DOM
    element intrinsic event properties in exactly the same way as it calls
    the functions programmers my directly assign to DOM element intrinsic
    event properties.
    <snip>

    No you don't, but what you don't know is the 'what' not the 'why'.

    Whenever the browser triggers this onclick event (and assuming - div -
    is a reference to a DOM element that is not the BODY element, as its
    name suggests) within the above function the expression - div === this
    - would be true.
     
    Henry, Oct 1, 2008
    #14
  15. yawnmoth

    dhtml Guest

    In which browser would |div| being the BODY element make any difference?
     
    dhtml, Oct 1, 2008
    #15
  16. Yes, indeed. There is no "HTML API" or "javascript API". The DOM
    implementation is the API that can be used e.g. with ECMAScript implementations.
    Maybe "slebetman" knows only IE and attachEvent(), whereas the latter is
    known to have the "`this' bug" described here in MSHTML. Also, the
    `onreadystatechange' event handler attribute (invalid)/property
    (proprietary) makes an exception here.


    PointedEars
     
    Thomas 'PointedEars' Lahn, Oct 1, 2008
    #16
  17. yawnmoth

    Henry Guest

    My statement does not say there would be a difference if - div - was -
    document.body -. It is as assertion about what pertains when it is
    not.
     
    Henry, Oct 2, 2008
    #17
  18. yawnmoth

    dhtml Guest

    Just curious why you mentioned about document.body there. I can't see
    how it makes any difference.
     
    dhtml, Oct 2, 2008
    #18
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.