1

I have one function inside another and I would like to call inner function from html document.

    <head>

<meta charset="utf-8">
<title></title>

<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="script.js"></script>
</head>

<body>
<input id="start" value="start" type="button" onclick="start()">
</body>

And JS.

function first()
{
    alert("First")

    function start()
    {
        alert("start");
    }
}

Why in this case button doesn't work? Thank you

1
  • The reason why the start function does not work is provided in many answers below. I would like to know why you want to do it this way Commented May 16, 2015 at 17:35

4 Answers 4

1

You have to readup on Javascript function/variable scoping. Your start function is defined inside your first function, so it is seen as local to that function. In order for it to be available/callable from anywhere within your script, it has to belong to the global, or for browers, the window object. There are a couple of ways you can achieve this.

1) Define the start variable as a property of the window object, outside of the first function. Then, inside the first function, assign a function reference to it.

var start = null; //defined variable outside of any function, and so has global scope

function first()
{
   alert("First")

   //assign a function to global variable `start`
   start = function()
   {
      alert("start");
   }
}

first(); //when you invoke first, it creates the inner function and assigns its reference to the global `start` variable, which can then be invoked
start();

2) Using closure, return a named function from the outer function:

function first()
{
   alert("First");

   var start = function()
   {
      alert("start");
   }

   return start;
}

3) A slight variation on the above, return an anonymous function from the outer function:

function first()
{
   alert("First");

   return function()
   {
      alert("start");
   }
}

In (2) and (3) above, when you call the function the first time, it will alert First, then it will return a function which you can execute immediately or assign to a variable for deferred execution. For example:

first()(); //alerts `First`, which returns a function reference, which reference is executed right away, to the alert `start`

//alerts `First`, then assigns returned function to the variable `start`
var start = first(); //`start` now holds a function reference which you can execute anytime, like so:

start(); //alerts `start`

Finally, as a quick reminder, it is strongly advised that you use event-listeners to assign events to your elements, rather than using the onclick or onwhatever attribute directly within the element. This also falls in line with the principle of separation of concerns.

Following from that, the updated code should look something like below:

HTML

<input id="start" value="start" type="button"><!-- notice no `onclick` attribute attached to it -->

Attach the click event listener to button using Javascript:

var startBtn = document.getElementById("start");
if (typeof startBtn.addEventListener === "function")
{
    startBtn.addEventListener("click", function(){first()()}, false);
}
else if (typeof startBtn.attachEvent === "function")
{  
    startBtn.attachEvent("onclick", function(){first()()}); 
}
else 
{
    startBtn.onclick = function(){first()()}
}
Sign up to request clarification or add additional context in comments.

1 Comment

+1 - nice, solid answer. I like the variation on returning function. Only thing I could possibly add is the obligatory mention that anything global is (generally) bad, and there are better ways to bind click event on an element than onclick handler (addEventListener, jQuery .on() - all used from within JS). ;)
1

That's cause your start function is encapsulated inside the first function scope.

One way is to expose your start to the global window object by assignment:

function first() {
    alert("First");
    window.start = function() { // encapsulated but available to the global window object
        alert("start");
    };
}

first(); // Still needed in order to execute it and expose `start`

A similar way exposing the start variable outside of the function scope:

var start = null; // (Says hello to window)

function first() {
    alert("First");
    start = function() {
        alert("start");
    };
}

// Here `start` is still null
first(); // Now `start` is a function

1 Comment

Would this be sort of an abstraction inversion antipattern?
1

The function keyword makes the name local to the function that it was defined in. Functions called from HTML attributes have to be global.

Then you have to call first() before you can call start().

var start;

function first() {
  alert("First");
  start = function() {
    alert("Start");
  };
}

first();
<input id="start" value="start" type="button" onclick="start()">

1 Comment

I've added a declaration outside the function.
0

why don't you make start a global function to call it from anywhere, even from you first function:

var start = function(){
        alert("start");
    },
    first = function(){
        alert("first");
        start();
    };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.