【问题标题】:Variable is not getting re-initialized when a function is being called again再次调用函数时变量未重新初始化
【发布时间】:2016-07-19 13:30:26
【问题描述】:

我从堆栈中的一项开始ar

我打算代码做的是:如果用户点击正确的链接(一台计算机已随机选择),我们继续到下一个“级别”,我们在堆栈中再添加一个元素。

在下一个级别中,用户必须按照它们在堆栈中的顺序选择 2 个正确的链接。一旦用户这样做,他应该进入下一个级别,依此类推。类似于西蒙说的游戏,我只是想用这个来模仿游戏的基本逻辑。

HTML:

<a href="javascript:void(0);" id="l1">Link 1</a>
<a href="javascript:void(0);" id="l2">Link 2</a>
<a href="javascript:void(0);" id="l3">Link 3</a>
<a href="javascript:void(0);" id="l4">Link 4</a>
<div id="log"></div>

Javascript

function check() {
  var index = 0;
  $('body').click(function(event) {
    var log = $('#log');
    alert(index);

    if ($(event.target).is(ar[index])) {
      log.html(index + ' ' + event.target.id + ' was clicked.');
      index++;

      if (index === ar.length) {
        //if all clicked elements corresponded to correct 
        //order in array and reached end of array
        level +=1;
        console.log("Passing to next level. ", level);
        randomId();
        console.log(ar);
        log.html(ar);
        check();
      }
    } 
    else {
      log.html(index + ' ' + event.target.id + ' was clicked. Is wrong');  
      index = 0;
    }
  });
}

var ar = [];  
divIds = ["#l1", "#l2", "#l3", "#l4"];
level = 1;
randomId();
check();

function randomId() {
  var min = 0;
  var max = 3;
  var id = Math.floor(Math.random() * (max-min+1)) + min;
  var selectedId = divIds[id];

  ar.push(selectedId);
  alert(ar);
}

但是,当我第二次调用 check() 函数时(当我们移动到堆栈中有 2 个元素的级别 2 时)尽管 var index = 0 是check() 函数。

我正在使用 console.log 和 alert 来捕获 index 的值,但它们的数量让我感到困惑。通过查看警报弹出窗口的数量,我的检查功能似乎就像一个循环。为什么我们在第二次调用该函数时没有得到一个干净的状态?

【问题讨论】:

  • 每次调用check() 时,都会向&lt;body&gt; 添加一个附加 事件处理程序。之前check() 调用中的处理程序不会神奇地消失。 IE。在两次调用check() 之后,单击&lt;body&gt; 将执行两个事件处理程序。如果这是问题所在,请在绑定新的事件处理程序之前删除现有的事件处理程序。
  • 为什么要一遍又一遍地附加点击处理程序?

标签: javascript jquery


【解决方案1】:

已更新 - 删除了不需要的 index 参数

如果我理解你的代码示例是正确的,你可以这样做

  • 添加 index level 作为check 函数的参数
  • 在调用check()(自调用)时将起始值传递给index/level
  • replace 去掉内部的check() index = 0;

这样,check 函数参数 index level 将像非全局静态变量一样工作,这很可能是您需要的。

我还为您的变量等推荐一个 app 对象,而不是使用全局变量。

旁注:我无法让实际代码按其应有的工作方式运行。在放弃了index 的使用和一些调整之后,它开始了。这是您希望它的工作方式吗,或者“索引”变量的目的是什么

var MyApp = {};
MyApp.ar = [];
MyApp.divIds = ["#l1", "#l2", "#l3", "#l4"];

(function check(level) {
  randomId();
  $('body').click(function(event) {
    var log = $('#log');
    if ($(event.target).is(MyApp.ar[level-1])) {
      log.html(event.target.id + ' was clicked.');
      if (level === MyApp.ar.length) {
        //if all clicked elements corresponded to correct 
        //order in array and reached end of array
        level++;
        console.log("Passing to next level. ", level);
        randomId();
        console.log(MyApp.ar);
      }
    } else {
      log.html(event.target.id + ' was clicked. Is wrong');
    }
  });
})(1);

function randomId() {
  MyApp.ar.push(MyApp.divIds[Math.floor(Math.random() * MyApp.divIds.length)]);  
  alert(MyApp.ar);
}
a {
  padding: 0 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="javascript:void(0);" id="l1">Link 1</a>
<a href="javascript:void(0);" id="l2">Link 2</a>
<a href="javascript:void(0);" id="l3">Link 3</a>
<a href="javascript:void(0);" id="l4">Link 4</a>
<div id="log"></div>

【讨论】:

  • 是的,谢谢,这正是我想要代码做的事情。我再次调用 check() 认为它正在重新启动函数,重置变量和所有内容。但正如你们所有人所提到的,它正在重新附加事件处理程序并将事情搞砸。附带说明一下,闭包能否帮助我理解为什么我的代码中似乎有多个 index 值,或者仅仅是因为多个事件处理程序?
  • @Joan 你说的是什么意思闭包会帮助你理解...
  • 我的意思是在我的水平上(我没有意识到我一次又一次地附加事件处理程序,这导致了不稳定的行为)将试图理解闭包帮助我更好地理解 JS 或只是让我更加困惑(我之前尝试过阅读它并没有很好地理解它)? javascript 相关论坛中不断出现闭包,当我试图理解一些不起作用的东西时,我倾向于认为这是因为我听说过但不理解的一些高级概念。
  • @Joan 然后我建议专注于学习 JS 基础知识,因为没有它们,闭包将非常难以理解,如果不是不可能的话。我已经做了一段时间了,我还有很多东西要学:)
  • @Joan 不过,看看这个页面,它可能会以比您之前阅读的更简单的方式解释它:developer.mozilla.org/en/docs/Web/JavaScript/Closures
【解决方案2】:

您在这里遇到的称为闭包。基本上,您将在另一个函数范围内定义的函数绑定到您的点击事件。所有的点击都引用了同一个outer index的作用域并对其进行修改。

阅读更多here

如果阅读后你仍然无法理解这里的问题,请在此处发表评论,我会尽力提供帮助,我只是不想重复其他人所说的话。

编辑:正如其他人指出的那样,您在这里还有另一个问题,即您多次绑定点击事件。您必须删除以前的绑定(甚至更好),只需更改值,不要绑定多个事件。

$('body').click(function(event){})

这行代码使您的点击生效。你不需要多次运行check(),因为一旦你“附加”了一次事件处理程序,你只需要检查值而不是一遍又一遍地重新绑定它。

换句话说,让你的check() 只运行一次,并将你的index 放在绑定的click 函数中,而不是放在外面,如果你希望它在每次点击时都重置。如果您希望它仅在一定数量的点击后重置,您需要将其保持在函数的关闭之外,如下所示:

function check(){
  index = 0;
  $('body').click(function(event){
    //NO INDEX HERE
  })
}

但是在这种情况下(这就是您现在所拥有的),您需要在某些条件下手动重置它,从您绑定到点击的函数中。例如if(ar &gt; neededNumber){index =0;}

【讨论】:

  • 实际上比这更糟糕,因为每次调用 check() 时都会创建 new 点击处理程序,并且每个处理程序都有自己封闭的 index
  • 但他确实只运行了一次 check() ,然后运行的是点击。但是,如果他每次重置他的值时都执行一次 check(),那么他最终会绑定多个函数,这确实使情况变得更糟,但从他的代码来看,他只调用了一次 check()。这是一个公平的观点。
  • 不,他一遍又一遍地检查......仔细看看,你会发现它
  • 天哪,我什至没有注意到那部分代码再次运行它,无论如何,这是两个独立的问题,都需要修复。
  • (我知道你已经看到了,但除了代码阅读之外,问题还明确指出它再次被调用:“但是当我第二次调用 check() 函数时 [...] ")
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-23
  • 1970-01-01
相关资源
最近更新 更多