1

I have two functions:

doSomething = function()  {
    alert(this);
}


var doSomethingElse = function() {
    alert(this);
}

This is my HTML:

<div id="banner-message">
  <p>Hello World</p>
  <button id='button1' onclick='doSomething()'>Do Something</button>
  <button id='button2' onclick='doSomethingElse()'>Do Something Else</button>
</div>

Why does doSomething() function call work while doSomethingElse() does not?

https://jsfiddle.net/brjdp56t/

Salman A
  • 262,204
  • 82
  • 430
  • 521
ashwnacharya
  • 14,601
  • 23
  • 89
  • 112

2 Answers2

2

There is a subtle difference. This creates doSomething in the global scope:

doSomething = function()

This creates doSomething in the current scope:

var doSomething = function()

The reason why the latter does not work is because you are executing this code inside a scope (closure, window.onload = function() {}, $(function() {}) etc) and the variable is therefore unavailable outside the scope. In the fiddle, the JavaScript code is wrapped inside window.onload = function() { var doSomethingElse = ... }.

Salman A
  • 262,204
  • 82
  • 430
  • 521
  • Brilliant, thank you. So this is basically due to how JSFiddle works? – ashwnacharya Oct 06 '18 at 12:49
  • @ashwnacharya Yes. But you can change fiddle options. Click on the JavaScript heading inside JavaScript tab and change the `LOAD TYPE` option. It defaults to `On Load`, change to `no wrap - bottom of ` if necessary. – Salman A Oct 06 '18 at 12:51
2

Why does doSomething() function call work while doSomethingElse() does not?

That will only be true if the code you've shown isn't at global scope (the code in your fiddle is wrapped in an onload handler provided by jsFiddle itself, see the options on the JavaScript pane — this is one of jsFiddle's more ridiculoussurprising default options). The reason is what I call The Horror of Implicit Globals. By not declaring doSomething in this code:

doSomething = function()  {
        alert(this);
}

...you're creating a global variable called doSomething. But by declaring doSomethingElse in this code:

var doSomethingElse = function() {
    alert(this);
}

...you're creating a local variable in the scope where that code exists.

Why does it matter? Because any function you call in an old onXYZ-attribute-style event handler has to be a global.

Instead:

  1. Use strict mode ("use strict") so that assigning to an undeclared identifier is an error instead of creating an automatic global.

  2. Use modern event handling (addEventListener and such) rather than onXYZ-attribute-style event handlers that require global functions.

  3. Put your script tag at the end of the document body, just before the closing </body> tag, so that all elements defined by your HTML have been created before the code runs. (Then you don't need onload or similar handlers.)

For example (Stack Snippets put the automatic script tag at the end of body for you):

"use strict";
// Scoping function to avoid creating globals
(function() {
    var doSomething = function()  {
        console.log("doSomething");
    };

    var doSomethingElse = function() {
        console.log("doSomethingElse");
    };
    
    document.getElementById("button1").addEventListener("click", doSomething);
    document.getElementById("button2").addEventListener("click", doSomethingElse);
})();
<div id="banner-message">
  <p>Hello World</p>
  <button id='button1'>Do Something</button>
  <button id='button2'>Do Something Else</button>
</div>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875