-2

To me, the following code seems reasonable enough:

$("#oneButton").click(
    alert("hello");
); 

It seems to say that when OneButton is clicked, please pop up an alert saying "hello".

However, in reality, the alert pops up regardless of whether the button is clicked or not.

One has to wrap alert("hello"); in an anonymous function, and THEN (and only then), the alert popping up will depend on clicking the button. To me this seems unnecessarily convoluted.

There must be a good reason why the designers of jQuery thought it acceptable for the alert in the code above to pop up even when the button hasn't been clicked. What is this reason?

thanks_in_advance
  • 2,603
  • 6
  • 28
  • 44
  • This is beginning to look like a 'primarily opinion-based' question. – Paul Oct 22 '14 at 06:15
  • Hard to know whether `alert` (which could also be `myFancyFunction`) does something you want to happen later or produces the function that does something that you want to happen later. – Thilo Oct 22 '14 at 06:17
  • Here you have a good article about that: http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/ – emerson.marini Oct 22 '14 at 06:19
  • Maybe you'll like Swift trailing closures (not that it helps any with Javascript). – Thilo Oct 22 '14 at 06:22
  • The authors of jQuery, a library of Javascript code, did not design `alert()` and can not change how it functions. It is a browser builtin and specified by HTML5. See https://developer.mozilla.org/en-US/docs/Web/API/Window.alert – Paul Oct 22 '14 at 06:29

4 Answers4

5

Fair question I guess, although I'm not a fan of the arrogance that came with it :)

Lets break this down a bit:

object.method(function() {
    alert('hi');
});

Your question is, why can't I skip the anonymous function?

What we're really doing here, is telling method to execute something at a later point. What's being executed is being supplied as a function.

We could simply give it a reference to a function instead!

object.method(alert);

Here's the problem, we've sent it a function, but now we can't send it any arguments. If we want to bring arument along to method, we must use ( and ).

As soon as those characters are included, the alert will instead get executed and the result of alert will get sent to method.

Now why can't this also be sent by reference? A very simple reason, you need some way to also pass the result of a function as an argument to another function, and the javascript engine cannot distinguish if your intent is to:

  • Send the result of a function as an argument to this other function, OR
  • Send a reference to the function with certain arguments to the other function.

Using ( and ) on a function means calling it immediately in almost every programming language, and javascript is no different.

There is a workaround:

object.method(alert.bind(this, "hi"));
Evert
  • 93,428
  • 18
  • 118
  • 189
  • `alert.bind` is very nice. But it only works for single functions, not for whole blocks. – Thilo Oct 22 '14 at 06:18
  • Well OP's example would have been a syntax error anyway with more than 1 statement. – Evert Oct 22 '14 at 06:19
  • @Evert: I think that's what he's complaining about. If we are hypothetically fixing it in language syntax, it should support blocks as well. – Thilo Oct 22 '14 at 06:20
  • Yea fair enough... Would love to see his hypothetical ABNF then :P It's obviously full of holes. – Evert Oct 22 '14 at 06:23
  • Coffeescript has something that's at least concise. Of course you still need to make it a function yourself. Swift has this trailing closures shortcut syntax (but that only works with strict typing). – Thilo Oct 22 '14 at 06:25
  • Would it be fair to say that any function calls [e.g. alert("hello");] in the code will be executed immediately regardless of where they are in the code, EXCEPT when they are inside function declarations? If not, then I guess my confusion is: why does the code inside .click() get executed even before the click has happened. It seems as if the interpreter reads through all the code at the start, even if it's hidden inside as-yet uncalled function blocks... is this correct? – thanks_in_advance Oct 22 '14 at 06:39
  • `click` is a bit too short of a method name as it doesn't accurately describe what it is. A super convoluted method name for that would be something more like `whenTheUserClicksCallThisFunction`. It's not so much a `click` that you're doing there, you are literally telling jQuery to execute a certain function after an event happen. – Evert Oct 22 '14 at 17:21
0

The problem is that Javascript has no macros (with the meaning of Lisp) and the only way to provide "code" to a function is by passing a function/closure object.

click is just a regular method and accepts a parameter that is "code" to execute when the button is clicked. As for any parameter however the expression passed to click is evaluated when making the call and not later when user clicks the button. To have click to work as you like the syntax should handle click differently than other function calls and this is what is allowed for example in Lisp by using macros instead of functions. Javascript has no macros and the syntax is fixed in the language: it doesn't have a click special form and you cannot create one.

The situation is not that terrible because Javascript syntax allows for inline anonymous functions so basically you just need to wrap your "code" parameters with function(){...} at the call site to get it working.

In Python for example things are a bit more annoying because only extremely simple functions can be specified inline as the lambda form can be used to specify anonymous inline functions but has serious limitations and doesn't allow any statement but just a single expression.

6502
  • 112,025
  • 15
  • 165
  • 265
0

Because .click() is a function and it may need a/some parameter/s to be used properly.

.click() alone will only trigger the event.

But .click(parameter) will do what's in the parameter after the event has been triggered. In this case parameter is a callback, i.e a function called after the main function finished. But for the callback to be called, you will have to create a function.

Either by naming one:

function alertThis(){
   alert('hello');
}

$("#oneButton").click(alertThis);

Or:

$("#oneButton").click(function(){
   alert('hello');
});
Xlander
  • 1,331
  • 12
  • 24
0

The language could only provide a less verbose syntax for functions (look at coffeescript), but it's ok for library functions to execute immediately, so you can wrap them and pass code around when needed.

What do you suggest instead? I can only think of one alternative approach where primitive API return themselves a function, but that would lead to uglier code when you need to combine multiple primitives (even with direct syntax support by the language):

$(btn).onClick(alert().andThen(blink()).andThen(log()));

And also you would be forced to call

alert()()

When you need to display the dialog immediately.

Raffaele
  • 20,627
  • 6
  • 47
  • 86
  • 1
    Strong vs. loose typing plays a role here. In C++ or Java, one could be quite specific about what a proper handler parameter to onClick(handler) is, such that the natural syntax for defining it and sending it to onClick() would preclude accidentally calling it, and if you did it anyway, it would probably generate a compile-time exception. But with loose typing as in Javascript, parameters to a function are allowed to be anything... – Paul Oct 22 '14 at 06:21