2

I have HTML code that looks like this:

<body>
    <label for="change0">What is your favorite number?</label>
    <input type="text" id="change0" />
    <div id="addStuff"></div>

    <script src="scripts/main.js"></script>
</body>

And I have JS that looks like this:

/** @type {number} */
var counter = 1;

function doStuff(id) {
    var thing = document.getElementById(id);
    thing.addEventListener('change', doMoreStuff);
}

function doMoreStuff() {
    counter++;
    var addStuff = document.getElementById("addStuff");
    var stuff = document.createElement("input");
    stuff.id = "change" + counter;
    stuff.type = "text";
    addStuff.appendChild(stuff);
    doStuff(stuff.id);
}

window.onload = function() {
    /** @constant */
    var SEED_ID = "change0"
    doStuff(SEED_ID);
};

The doMoreStuff() function recursively calls the doStuff() function. Does JavaScript manage the memory properly, or am I doing this incorrectly?

BackPacker777
  • 673
  • 2
  • 6
  • 21
  • if doStuff did call doMoreStuff, your code would crash. – JMP Mar 19 '15 at 12:21
  • 1
    Rather than passing the ID into your `doStuff` function you could just pass in the element. This would mean you'd not have to give an `id` attribute to your dynamically-added `input` element at all. `doStuff(document.getElementByID(SEED_ID))` in your `window.onload`, then `doStuff(stuff)` in your `doMoreStuff()` function. – James Donnelly Mar 19 '15 at 12:21
  • I don't think you understand what is meant by recursion. A true recursive call would be if doStuff called doStuff, which then yes, you could run into problems. There is nothing wrong with your code, and in fact, it's good programming practice to separate your code into multiple functions calls, as it makes it easier to follow and maintain. – Russ Mar 19 '15 at 12:23
  • @russ - I was worried that doMoreStuff() never really gets to it's close curly brace, thereby unloading out of memory. I would love to learn more if you have a good link. Thanks! – BackPacker777 Mar 19 '15 at 12:36
  • The only reason doMoreStuff() would not get to its end (the close brace) would be if something in doStuff() errored. if doStuff() succeeds, it returns to doMoreStuff(). Since doMoreStuff() has no more lines after doStuff(), then it returns to the place that called doMoreStuff(). – Russ Mar 19 '15 at 12:39

2 Answers2

4

The doMoreStuff() function recursively calls the doStuff() function.

That's not really mutual recursion, as doStuff doesn't call doMoreStuff - it only sets it up as a handler to be called.

Does JavaScript manage the memory properly

Yes. Asynchronous "recursion" (sometimes dubbed pseudo-recursion) does not grow the call stack, it's much like tail recursion.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

What you have isn't recursion. The doStuff function just binds an event handler to an event, and you reuse the function in the event handler.

It's similar to recursion, but waiting for the event to happen breaks the chain. You need to think of handling event in a different way than procedural code, otherwise you will have difficulties when you have several different events to consider.

Reusing code is a great tool, but in this case it doesn't do very much. The way that you bind the events are not very similar, so you can just repeat the addEventListener call in the two places, and the code gets even simpler:

function doMoreStuff() {
    counter++;
    var addStuff = document.getElementById("addStuff");
    var stuff = document.createElement("input");
    stuff.id = "change" + counter;
    stuff.type = "text";
    addStuff.appendChild(stuff);
    stuff.addEventListener('change', doMoreStuff);
}

window.onload = function() {
    document.getElementById("change0").addEventListener('change', doMoreStuff);
};
Guffa
  • 687,336
  • 108
  • 737
  • 1,005