【问题标题】:Trouble with closure in Javascript loopJavascript循环中的关闭问题
【发布时间】:2017-01-10 21:12:39
【问题描述】:

过程:在我正在制作的游戏中,有一个 for 循环应该将一个值保存在一个数组中。该值随每次迭代而变化。问题:当循环完成运行时,数组的每个元素都是相同的,都显示最新的值。
我知道这个问题很常见,并且在过去 2 天里我做了很多不同的调整和尝试来解决它。

0) 我尝试尽可能将事物分成单独的函数。
1) 我尝试用“let”定义我的循环计数器,以便它们具有本地范围。
2)我尝试将我的分配包装在一个自执行函数中,以便它立即发生,在下一次循环迭代更改它之前保留 currentOn 的值。我的计数器是变量 c。

(function(c2, currentlyOn2) {
  onAtSameTime[c2] = currentlyOn2;
  return 0;
})(c, currentlyOn);

3) 我尝试了 #2 并添加了返回函数的功能,但仍然没有保存 currentOn 的值。无论如何,这个选项对我来说不是一个好选项,因为重点是我提前做了一些计算,所以我的游戏会有一个快速的动画循环。

onAtSameTime[c] = (function(currentlyOn2) {
  return function() {
    return currentlyOn2;
  };
})(currentlyOn);

我已经厌倦了用头撞墙。谁能解释我做错了什么?

更多详情,请查看jsfiddle I made。问题区域在第 59 行,使用一个简单的赋值:

onAtSameTime[c] = currentlyOn;

【问题讨论】:

  • currentlyOn 只是一个指向数组值存储位置的指针。每个 [c] 索引都将包含相同的指针,因此也将访问相同的值。使用本地化数组而不是 currentOn 来避免这种情况,或者在应该有多个数组时考虑重构您的方法以避免一个数组。
  • 不,这与闭包无关。在您的循环之后没有执行任何函数。您似乎对数组迭代、数组克隆或您的算法有问题。
  • 您需要发布更多代码,以便我们看到您做错了什么。
  • 此处发布您的代码,而不仅仅是在 jsfiddle。您可以使用Stack Snippets 使其可执行

标签: javascript for-loop closures


【解决方案1】:

onAtSameTime[c] = currentlyOn; 设置onAtSameTime[c] 等于currentlyOnreference,因为currentlyOn 是一个数组,而不是原始值。每次迭代都会更新该引用。您可以通过在将其添加到 onAtSameTime 数组之前创建数组的副本来解决此问题。像onAtSameTime[c] = [].concat(currentlyOn); 这样的东西可以解决问题。

查看您的 JSFiddle 的这个分支:https://jsfiddle.net/L2by787y/

【讨论】:

  • 感谢您的解决方案和详细解释!你的答案对我有用。
【解决方案2】:

您可以从currentlyOn 复制一份以分配给onAtSameTime[c]。这会保留值,但不会保留对同一数组的引用。

onAtSameTime[c] = currentlyOn.slice(); // use copy

"use strict";
function log(text) {
    document.getElementById("logbox").innerHTML += JSON.stringify(text) + "<br>";
    return 0;
}

function whichSwitchesAreOn() {
    var currentlyOn = [],
        flickedSet,
        flickedOne,
        turningOnCheck;

    for (var c = 0; c < switchesToggled.length; c++) {
        flickedSet = switchesToggled[c];
        for (var d = 0; d < flickedSet.length; d++) {
            flickedOne = flickedSet[d];
            turningOnCheck = currentlyOn.indexOf(flickedOne);
            if (turningOnCheck == -1) {
                currentlyOn.push(flickedOne);
            } else {
                currentlyOn.splice(turningOnCheck, 1);
            }
        }
        log("currentlyOn: " + currentlyOn);
        onAtSameTime[c] = currentlyOn.slice(); // use copy
    }
    return 0;
}

var switchesToggled = [[0], [1, 2], [0], [2], []],
    onAtSameTime = [];

whichSwitchesAreOn();
log(onAtSameTime);
&lt;div id="logbox"&gt;&lt;/div&gt;

【讨论】:

  • onAtSameTime[c] = currentlyOn.slice(); 更简单,一行更短
  • 非常感谢您的宝贵时间。我接受了 Eric Gibby 的回答,因为它的解释更详细,但你的回答也有效。
【解决方案3】:

你说你试过让?

你是否让 currentOn = [] 在 for 循环中?

  for(var c = 0; c < switchesToggled.length; c++) {
      let currentlyOn = [];

【讨论】:

  • 它只处理一个没有let的作业。
  • 很遗憾,循环的每次迭代都必须能够记住currentOn的前一个值,所以我无法在循环内定义它。
猜你喜欢
  • 2020-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多