Javascript,闭包中的奇怪行为

发布于 2024-08-21 19:28:55 字数 1463 浏览 4 评论 0 原文

我正在玩弄(阅读:学习)Javascript,并发现了一些我理解的东西,看起来很奇怪。它与闭包和引用有关,似乎“失去”了它对浏览器的重要性。

我使用的浏览器是Chromium 5.0.307.7

无论如何,这里有一些代码:

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();
}

这里发生的情况是第一个参数被写入正确的 HTMLElement,但后面的所有参数都没有。似乎发生的情况是,在第一个参数之后,以下参数被写入现在由“elem”引用的某个其他元素。

我还应该提到,这似乎只有当我在调用这个函数后直接写一些东西时才会发生,就像这样:

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

如果我在调用这个函数后不写任何东西,它似乎工作正常。

如果我将上面的代码更改为:

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();
}

一切都很好。我的问题是,第一个版本的幕后到底发生了什么?

编辑:按照 Bryan Matthews,我不确定如何提供测试页面而不使这个问题过于混乱。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不交电费瞎发啥光 2024-08-28 19:28:55

我怀疑这是 DOM 问题,而不是 JavaScript 问题。

我的猜测是,某些东西正在改变您尝试逐步写入的元素的祖先。例如,如果设置了元素父元素的 innerHTML (我认为甚至设置为完全相同的字符串),则您所拥有的元素引用将指向不再位于 DOM 中的元素。每次通过 ID 重新获取元素就可以解决这个问题。

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.

那小子欠揍 2024-08-28 19:28:55

如果您要替换 elem 祖先的 innerHTMLbody 元素,根据您的示例),则 elem< /代码> 不再存在。当 step 位于原始 elem 被销毁之后,elem 引用的内容将是其他内容。

浏览器正确的做法可能应该是删除 elem 引用,但它看起来并没有这样做。

If you're replacing the innerHTML of an ancestor of elem (the body element, as per your example), then elem no longer exists. When step is after the original elem is destroyed, what elem is referencing is going to be something else.

The correct thing for the browser to do should probably be to remove the elem reference, but it doesn't look like it's doing that.

风吹短裙飘 2024-08-28 19:28:55

我的猜测是,执行 setTimeout(step, 500); 回调几乎不知道 this 是谁 - 无论您是否正在调用当前元素的 step或者也许HTMLElement.prototype.writeInSteps.step()

同时在两个不同的元素上尝试第二个代码(以便第二个 writeInSteps 在第一次超时之前出现)。我很确定它不会达到您的预期。

当然,杰夫也可能是对的。 innerHTML 根据规范是只读的,写入它可能会也可能不会重建整个树(并杀死所有引用)。

my guess is, execution of setTimeout(step, 500); callback has very little idea who this is - whether you're calling current element's step or maybe HTMLElement.prototype.writeInSteps.step() ?

Try your second code on two different elements simultaneously, (so that second writeInSteps comes before first timeout). I'm pretty sure it won't do quite what you expect.

Of course Jeff can be right too. innerHTML is read-only by specification, and writing to it may or may not rebuild the whole tree (and kill all the references).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文