-2

I am taking a web development class. Today the teacher gave us a piece of code that raised some questions that I haven't been able to satisfactorily solve through my own searching. The code in question was essentially this:

<script>
function selectmouse(e){
...
...
}

document.onmousedown = selectmouse;
</script>

My first question, is this a legitimate way of calling functions? Is this something that is done? I am of course familiar with the typical way of calling functions from HTML elements, for example

<body onmousedown="selectmouse(event)">

The code was supposed to be calling the function and passing it the event object for the onmousedown. After playing with the code for a while I found a few unusual things.

First, if I put parenthesis after the function call, like I am used to doing (i.e. selectmouse();), then the function resolved immediately upon loading the page, with a value of 'undefined' for the variable. This makes intuitive sense to me, because I assume the browser is treating it like a variable assignment and therefore calling the function as it parses the code, as it normally would to assign a variable.

However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to. It would call the function when the mouse was pressed in any part of the body, and it sent the event object as the variable for the function. But I can't figure out why. I can't find reference to anything similar to it online, and I've never seen anything like it before. Is this a legitimate way to do something like this? Or is this bad code that happens to be working for some reason and would probably cause problems in the future? Why is it working?

Phil
  • 157,677
  • 23
  • 242
  • 245
  • For call to a function you must have select document or its html .... – ashbuilds Mar 04 '14 at 05:00
  • possible duplicate of [What is meant by 'first class object'?](http://stackoverflow.com/questions/705173/what-is-meant-by-first-class-object) – Phil Mar 04 '14 at 05:05
  • 1
    Ideally, it should be `document.addEventListener('mousedown', selectmouse, false)`. See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener – Phil Mar 04 '14 at 05:07
  • 2
    I'd like to call into question your accusation that your teacher is *incompetent*. It seems she at least knows more than her students which I'd say is a good start. – Phil Mar 04 '14 at 05:09
  • 1
    Agreed @Phil. It's like writing "My totally incompetent coworker used in-line styles AND tables for an HTML e-mail!! YUCK...LOL.Everyone knows those are bad... Anyway, why doesn't this work..." – Jack Mar 04 '14 at 05:15
  • While I probably shouldn't have led this question with that statement, I assure you the accusation was based off of much more than just this code piece. – SometimesDirty Mar 04 '14 at 05:17

4 Answers4

1
document.onmousedown = selectmouse;  //note: never do this except in old browsers

However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to.

That's not weird. You are passing the reference of the function to the browser, not executing it.

For example, you have this function:

function callback(){
    alert("clicked!");
}

document.body.onclick = callback;

You pass the reference to onclick and the browser will know what function to call when the event is triggered. But if you do it like this:

document.body.onclick = callback();

This will be evaluated into:

document.body.onclick = alert("clicked!");
//Note that this is simplified explanation to visualize what is happening.
//The returned value of alert() is not assigned to onclick.
//To be exact the returned value of callback() is the one that is being assigned.
//Similar to:
//  ...onclick = (function(){ alert("clicked!"); })();

Then you will see an alert, and the browser will continue executing the rest of the code:

document.body.onclick = undefined;

<body onmousedown="selectmouse(event)">     <!-- Don't do this too -->

The parentheses are necessary because this code is not executed instantly. It is only executed when the event is triggered.


Anyway, you shouldn't attach events both using .onmousedown or onmousdown="...". There is a better way of doing it:

element.addEventListener("mousedown", callback, false);

Reason: If you use the onmousedown property, you can only attach one mousedown event. In most cases you would want to attach more than one.

Also attaching events inline might cause security problems (cross-site scripting), and that is exactly why Google decided to prohibit all developers from using them in developing Chrome apps/extensions.

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • I wouldn't say *never*. See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener#Older_way_to_register_event_listeners (scroll down to *Older way to register event listeners*, MDN's title links are broker on that page) – Phil Mar 04 '14 at 05:12
  • Too true! I just think *never* is a bit strong :) – Phil Mar 04 '14 at 05:16
  • Ok I've worked my way through everything you said here along with the google link and the mozilla link. Thanks for the help. I'm pretty sure I've got a pretty good handle on it, although of course I'll need to practice with it. I'm surprised to hear that inline calls are not supposed to be used anymore, considering how ubiquitous they have been in everything I've seen or worked with so far. – SometimesDirty Mar 04 '14 at 05:47
  • @SometimesDirty - If you take a look at the source of your favorites sites, you would find that most of the time inline events are not used anymore. They are outdated and not so good for future maintenance. And who still manually attach events when you have jQuery and AngularJS? ;) – Derek 朕會功夫 Mar 04 '14 at 08:21
  • Your sample regarding the onlick/alert is not correct. onclick will remain undefined as the callback function does not return anything – Robert Slaney Mar 05 '14 at 23:17
  • @Derek朕會功夫, the bit that is wrong is `document.body.onclick = alert("clicked!");`. The browser will not unwrap the function body and assign it to the handler – Robert Slaney Mar 06 '14 at 01:46
  • @RobertSlaney - I was just trying to describe it in a way that can be easily understood. Perhaps I should add comments to clarify this bit. – Derek 朕會功夫 Mar 06 '14 at 02:05
0

This is legitimate code and is working as it should.

The way you are comfortable with is just a method we tried while the web was evolving, but at present we should better use the second way you showed, although its changed bit more to make you understand it in a better way using event bindings.

When you do

function selectmouse(e){
...
...
}

javascript will create a variable named selectmouse and save the function in that variable. So selectmouse is a variable of type function with the function body as its value.

document on the other hand can be related to class or specifically an object which is an instance. Each document and each HTML element or DOM node can have in it variables to store the functions to be called on user events like onmousedown.

so when doing

document.onmousedown = selectmouse;

we are inturn saying

when mousedown happens in document, the function named selectmouse should be called

If you do

document.onmousedown = selectmouse();

it means

run the function selectmouse immediately and get the result, assign the result to onmousedown event of the DOM Node document.

And if you ask why this is taken apart from the form

<body onmousedown="selectmouse(event)">

To answer in a simple way, HTML is Hyper Text Markup Language, its sole purpose is to represent formatted data, the quick evolution of web inturn made it deranged with behaviours like this and presentation code like inline css. So to make behaviour and presentation out of HTML and thus a better design we do this.

Please take time to take a look at how you can bind a function to an event which is the current tradeoff in doing this same thing.

For a detailed explanation please check the events sectio of ppk blog here

sabithpocker
  • 15,274
  • 1
  • 42
  • 75
  • I'm confused by this. The second way I showed IS the way I'm comfortable with, where as the first way is the one I have a question about. – SometimesDirty Mar 04 '14 at 05:12
  • Your answer makes a lot more sense now, thanks a lot. I am going to spend some time working my through the link you provided. – SometimesDirty Mar 04 '14 at 05:51
-1

I think that is correct, because the function is being called within the script as if it were an object, to me is not the best way to do it, I would have like this (with jquery):

$(document).mousedown(function (event) {
  // here the content of the function
 });
jorgeregidor
  • 208
  • 2
  • 13
-2
<body onmousedown="selectmouse(event)">

In this example the browser evaluates the result of the expression selectmouse(event) and assigns it to the onmousedown property of the body, event is undefined and the selectmouse doesn't return anything so it's result is undefined.

It is equivalent of the following if it was inside a script tag

<script>
    function selectmouse(e) {
    }

    document.body.onmousedown = selectmouse(event);
</script>

<body onmousedown="selectmouse">

When you remove the () you are assigning a function to the onmousedown property. Now the browser fires your callback method whenever the mousedown event is raised and it bubbles up to the body, passing the current event as the parameter you're declaring as "e". If another element also had an onmousedown event handler declared but it cancelled the event ( by calling event.cancelBubble = true ) the body's onmousedown handler will not be invoked.

<script>
    function selectmouse(e) {
    }

    document.body.onmousedown = selectmouse;
</script>
Robert Slaney
  • 3,712
  • 1
  • 21
  • 25