Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript, odd behaviour in a closure

I was toying (read: learning) around with Javascript and came across something to my understanding, seems very odd. It has to do with closures and a reference that seems to 'loose' its importance to the browser.

The browser I am using is Chromium 5.0.307.7.

Anyway, here's some code:

HTMLElement.prototype.writeInSteps = function() {
  var i = 0;
  var elem = this;
  var args = arguments;

  function step() {
    elem.innerHTML += args[i];

    if(i < args.length) {
      i += 1;
    } else {
      elem.innerHTML = "";
      i = 0;
    }


    setTimeout(step, 500);
  }

  step();
}

What happens here is that the first argument gets written to the correct HTMLElement, but all the ones after does not. What seems to happen is that after the first argument, the following arguments are written to some other element that is now being referenced by 'elem'.

I should also mention that, this only seems to happen when I write something directly after calling this function, like this:

div.writeInSteps("This", " is", " not", " working");
$id("body").innerHTML += "Doh!";

If I refrain from writing anything after calling this function, it seems to work ok.

If I instead change the above code to:

HTMLElement.prototype.writeInSteps = function() {
  var i = 0;
  var e = this.id;
  var args = arguments;

  function step() {
    var elem = $id(e);
    elem.innerHTML += args[i];

    if(i < args.length) {
      i += 1;
    } else {
      elem.innerHTML = "";
      i = 0;
    }


    setTimeout(step, 500);
  }

  step();
}

Everything is dandy. My question is, what's really happening behind the scenes in the first version?

EDIT: Updated with requested details about "...write something directly after..." and browser usage as requested by ntownsend. Bryan Matthews, I'm not sure how to provide a test page without making this question overly cluttered though.


1 Answers

I suspect this is a DOM issue, not a JavaScript issue.

My guess is that something's mutating an ancestor of the element to which you're trying to write in steps. For example, if innerHTML of the element's parent is set (even to the exact same string, I think), the element reference you have will be to an element that's no longer in the DOM. Re-getting the element by ID each time would work around that problem.

like image 162
Jeff Walden Avatar answered Mar 31 '26 15:03

Jeff Walden



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!