Javascript 我应该为一个经常运行的函数使用LET全局声明一个变量吗?

Javascript 我应该为一个经常运行的函数使用LET全局声明一个变量吗?,javascript,ecmascript-6,Javascript,Ecmascript 6,这里最相关的答案不是指块范围的let,而是指挂起的var。我似乎无法得到一个明确的答案 我有一个全局声明的变量,初始化一次: let firePaused = false; 然后是键盘处理程序中的一个函数,每次我按下按钮时都会运行该函数: function actOnKeyPress() { if (rightPressed) { game.hero.rotate(game.hero.speed); } else if (leftPressed) { game.hero

这里最相关的答案不是指块范围的let,而是指挂起的var。我似乎无法得到一个明确的答案

我有一个全局声明的变量,初始化一次:

let firePaused = false;
然后是键盘处理程序中的一个函数,每次我按下按钮时都会运行该函数:

function actOnKeyPress() {
  if (rightPressed) {
    game.hero.rotate(game.hero.speed);
  } else if (leftPressed) {
    game.hero.rotate(-game.hero.speed);
  }
  if (!firePressed) {
    firePaused = false;
  }
  if (firePressed && options.numberOfBullets > 0) {
    if (!firePaused) {
      fireBullet();
      firePaused = true;
    }
  }
}
(与问题无关,但其目的是只允许玩家开火一次,在玩家再次开火之前,需要有一个键控事件)

根据干净代码的规则,我应该在函数顶部声明变量。。。但这意味着每次我按下一个按钮,它都会被重新声明

上面写着

初始化:当您声明一个变量时,它会自动 初始化,这意味着内存由 JavaScript引擎

所以每次使用let关键字时,我都会创建一个全新的变量


我是否应该在函数的开头写一个条件来检查
firmaused
是否已经声明,如果没有声明它呢?这似乎太过分了。

如果您的变量是在全局范围内声明的,那么使用
let
var
实际上并不重要

这些功能相同:

让myVar=123;
函数doStuff(){
console.log(myVar);
}

doStuff()
不,您不应该创建全局变量(无论如何也不要使用
let

是的,如果希望在调用之间共享它,则应该在函数外部声明它

您可以使用闭包实现这一点,使用任何类型的模块模式—从ES6模块到IIFE,再到简单的块范围

// ES6 module
let firePaused = false;
export function actOnKeyPress() {
  // use `firePaused`
}

这个问题实际上与
let
var
本身无关——它是关于范围的。 变量应该在保持程序正常运行的最小范围内声明。全局变量应该是最后的手段

因此,在您的情况下,您不需要全局变量来实现不在每次函数调用时重新声明变量的目标。您只需要创建另一个作用域。由于所有代码首先都应该被排除在全局范围之外,因此您的代码应该至少有一个子范围,这通常是通过创建实现的:

(function(){
  let firePaused = false; // This is scoped to the entire module, but not Global

  function actOnKeyPress() {
    if (rightPressed) {
      game.hero.rotate(game.hero.speed);
    } else if (leftPressed) {
      game.hero.rotate(-game.hero.speed);
    }
    if (!firePressed) {
      firePaused = false;
    }
    if (firePressed && options.numberOfBullets > 0) {
      if (!firePaused) {
        fireBullet();
        firePaused = true;
      }
    }
  }
})();

看起来您正试图在多个位置维持角色的(英雄)状态。这将变得越来越难以在全局范围内维护,因为每个角色的动作/状态将添加到全局变量中

根据@jeff huijsmans的建议,我认为您应该在
游戏
对象中保持状态

这可以通过以下几种方式进行定义:

  • game.state.firemaused
    -这会将游戏状态锁定为单个角色,但最好包含角色射击的状态
  • game.hero.firemaused
    -这允许每个角色保持自己的射击状态。这还有一个额外的好处,就是能够添加更多具有触发状态的角色

  • 另一方面,这里的大多数答案似乎都试图解决范围问题。全局定义变量并尝试在函数外部维护状态变得非常难以理解/读取/测试。在这个话题上会有很多意见。幸运的是,对于您的根本问题,您可以通过使用预先存在的状态对象来避免此问题。

    似乎您有一个全局变量,
    game
    。那游戏.状态.火力支援呢?这样,如果你把所有与游戏状态相关的变量都放在那里,你甚至可以很容易地保存游戏。有没有可能你可以返回true或false而不是设置一个变量?Sitepoint注释充其量是误导性的,在我看来这完全是错误的。实际上我建议你一直这样做。@Bergi:
    window
    不是有点不对劲吗,使用而不是正确的作用域操作/用法?我不关心变量在
    窗口中是否可用,问题在于。(现在找到了正确的链接)。对于这个问题,编码约定不是有点超出了“范围”吗?@Cerbrus当那些“模式”(“约定”完全是另一回事)修改范围时不会这样做。吹毛求疵:“所有代码都应该不在全局范围内”<这是一个约定。如何做到这一点,是通过实现某种模式来实现的。@Cerbrus(更挑剔)这是一种“最佳实践”。“约定”是一种普遍接受的做事方式(即命名约定)。有很多方法可以避免全球范围。先生,你只是挑剔了我。
    
    // block scope
    var actOnKeyPress;
    {
      let firePaused = false;
      actOnKeyPress = function actOnKeyPress() {
        // use `firePaused`
      };
    }
    
    (function(){
      let firePaused = false; // This is scoped to the entire module, but not Global
    
      function actOnKeyPress() {
        if (rightPressed) {
          game.hero.rotate(game.hero.speed);
        } else if (leftPressed) {
          game.hero.rotate(-game.hero.speed);
        }
        if (!firePressed) {
          firePaused = false;
        }
        if (firePressed && options.numberOfBullets > 0) {
          if (!firePaused) {
            fireBullet();
            firePaused = true;
          }
        }
      }
    })();