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

时间:2018-05-02 14:21:45

标签: javascript ecmascript-6

这里最相关的答案并不是指 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;
    }
  }
}

(与问题无关,但它的目的是只允许玩家射击一次,在他们再次射击之前需要有一个keyup事件)

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

它在这里说https://www.sitepoint.com/how-to-declare-variables-javascript/

  

初始化:当您声明变量时,它是自动的   初始化,表示由变量为变量分配内存   JavaScript引擎。

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

我是否应该在函数开始时编写一个条件来检查是否已声明firePaused,如果没有声明它?这似乎完全矫枉过正。

4 个答案:

答案 0 :(得分:3)

如果您的变量是在全局范围内声明的,那么使用letvar并不重要。

这些在功能上是相同的:

let myVar = 123;
function doStuff() {
  console.log(myVar);
}
doStuff();

var myVar = 123;
function doStuff() {
  console.log(myVar);
}
doStuff();

当你在块中声明它们时,varlet之间的差异变得很大:

if(true) {
  var foo = 1;
}
if(true) {
  let bar = 2;
}

console.log("var foo:", foo);
console.log("let bar:", bar);

如您所见,let声明仅限于其包装块范围。 var声明忽略了块范围。

答案 1 :(得分:3)

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

根据@ jeff-huijsmans的建议,我相信您应该在game对象中保持状态。

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

  1. game.state.firePaused - 这会将您的游戏状态锁定为单个角色,但最好包含角色射击的状态。
  2. game.hero.firePaused - 这允许每个角色保持自己的拍摄状态。这还有一个额外的好处,就是能够使用触发状态添加更多字符。
  3. 顺便说一句,看起来这里的大多数答案都试图解决范围问题。全局定义变量并尝试维持函数之外的状态变得非常难以理解/读取/测试。关于这个话题会有很多意见。幸运的是,对于根本问题,您可以通过使用预先存在的状态对象来避免这种情况。

答案 2 :(得分:2)

这个问题实际上与letvar无关,本身就与范围有关。

变量应在保持程序功能的最小范围内声明。全局变量应该是最后的手段。

因此,在您的情况下,您不需要全局变量来实现在每次函数调用时不重新声明变量的目标。您只需要创建另一个范围。由于所有代码都应该首先保留在全局范围之外,因此您的代码应该至少有一个子范围,通常使用 Immediately Invoked Function Expression 来实现,这会创建的 "Module Pattern"

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

答案 3 :(得分:1)

不,你不应该创建一个全局变量(而不是let) 是的,如果你想让它在呼叫之间共享,你应该在函数之外声明它。

您可以使用任何类型的模块模式 - 从ES6模块到IIFE到简单的块范围。

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

// IIFE
var actOnKeyPress = (function() {
  let firePaused = false;
  return function actOnKeyPress() {
    // use `firePaused`
  };
}());

// block scope
var actOnKeyPress;
{
  let firePaused = false;
  actOnKeyPress = function actOnKeyPress() {
    // use `firePaused`
  };
}