javascriptttt
javascriptttt

Reputation: 730

How to use onclick with a function expression rather than a declared function?

I have a button

var startButton = $('#startButton').get(0);

that I attach the vanilla javascript onclick method to the button and call start on click.

startButton.onclick = start;

I want to use a function expression but (due to hoisting?) this doesn't call start

var start = function() {
  console.log('requesting local stream');
  startButton.disabled = true;
  getUserMedia(constraints, gotStreamSuccess, errorCallback);
}

A declared function does

function start() {
  console.log('requesting local stream');
  startButton.disabled = true;
  getUserMedia(constraints, gotStreamSuccess, errorCallback);
}

How can I write

startButton.onclick = start;

so that it works with a function expression?

Thanks

Upvotes: 9

Views: 2250

Answers (3)

Rigotti
Rigotti

Reputation: 2862

The event attachment must occur after the creation of the function expression.

Checkout about this example

<button id="click">Click</button>
<button id="click2">Click2</button>

$(function(){

  var startButton = $("#click").get(0);
  var startButton2 = $("#click2").get(0);

  startButton.onclick = clickFunc; // wont work

  var clickFunc = function() {
    alert('click');
  };

  startButton2.onclick = clickFunc; // work
});

Upvotes: 0

rhino
rhino

Reputation: 13881

Judging by the description of your problem, it seems that you declare (and define) start after assigning it to startButton.onclick. In such case, startButton.onclick will indeed be undefined.

What is hoisted is the variable itself - your code knows it has been declared, but doesn't yet know its value, as the assignment takes place exactly where you have it in the code. Think of it this way: when you use the var keyword, you declare a variable, which, however, is not yet defined. If you happen to immediately assign a value to it, the new value is not visible to the code above the assignment.

Consider the following example:

var a = 1;
console.log(a);
var a = 2;
var a = 3;

Which one of the three values would you expect to be logged in the console? 1, 2 or 3?
You can use var for a single identifier as many times as you want (though I would not recommend it); consecutive declarations are simply ignored, only the assignments are taken into account. Because of that, an assignment cannot be hoisted.

Function declarations, however, are finite in some sense, they can be hoisted in their entirety and that is the reason why using a function declaration worked in your case.

To solve the problem, you could indeed use a function declaration, or perform the variable assignment before startButton.onclick = start; (and I think you don't really need a variable in this particular case, a function declaration is perfectly suitable for this task).

Note that you could also do:

startButton.onclick = function() { // I'm a function expression too!
    // do something here
}

Upvotes: 2

Adam
Adam

Reputation: 2077

I would agree with you that it's a hoisting issue, you'll have to look within your code to hoist it appropriately before setting startButton.onclick = start;.

Here's what MDN has to say about the syntax: Syntax for on click

It specifically mentions that the function can either be declared or expressed. Which, to me, leads again to the hoising, because function declarations are automatically hoisted.

The MDN for onclick uses a function declaration. I changed the example in this JSFiddle to use a function expression, as you would like to use. With proper hoisting, it is calling the correct method when you click the button.

Upvotes: 2

Related Questions