简体   繁体   中英

Should I declare a variable using LET globally for a function that runs constantly?

Most relevant answers here do not refer to let , which is block scoped, but to var , which is hoisted. I can't seem to get a definitive answer to this.

I have a variable declared globally that initializes once:

let firePaused = false;

and then a function in the keyboard handler that is running everytime I press a button:

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

(not relevant to the question, but it's purpose is to only allow the player to fire once, there needs to be a keyup event before they can fire again)

By the rules of clean code I should declare the variable at the top of the function... BUT that means it will be redeclared everytime I press a button.

It says here https://www.sitepoint.com/how-to-declare-variables-javascript/

Initialization: When you declare a variable it is automatically initialized, which means memory is allocated for the variable by the JavaScript engine.

So I would be creating a whole new variable each time the let keyword is used.

Should I go to the bother of writing a conditional at the start of the function to check if firePaused is declared yet, and if not declare it? That seems total overkill.

If your variable is declared in the global scope, then it doesn't really matter if you use let or var .

These are functionally identical:

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

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

The difference between var and let becomes significant when you're declaring them in blocks:

 if(true) { var foo = 1; } if(true) { let bar = 2; } console.log("var foo:", foo); console.log("let bar:", bar); 

As you can see, the let declaration is restricted to its wrapping block scope. The var declaration ignores block scope.

Looks like you are attempting to maintain a character's (hero) state in multiple locations. This will become more and more difficult to maintain in a global scope as each character's actions / states will add to the global variables.

As per @jeff-huijsmans suggestion, I believe you should maintain the state inside your game object.

This could be defined in a few ways:

  1. game.state.firePaused - This locks your game state to a single character, but will better contain the state of a character shooting.
  2. game.hero.firePaused - This allows each character to maintain their own shooting state. This also has the added benefit of being able to add more characters with firing states.

As an aside, it looks like most of the answers here are attempting to address the scope issue. Defining variables globally and attempting to maintain a state outside of a function becomes very difficult to understand/read/test. There will be a lot of opinions on this topic. Fortunately for your root issue you can avoid this by using your pre-existing state object.

This question really has nothing to do with let vs. var , per se - it's about scope in general.

Variables should be declared in the smallest scope that keeps the program functional. Global variables should be a last resort.

So, in your case, you don't need a Global variable to achieve your goal of not re-declaring the variable upon each function call. You just need to create another scope. Since all code should be kept out of the Global scope in the first place, your code should already have at least one sub-scope, which is often achieved with an Immediately Invoked Function Expression , which creates the "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;
      }
    }
  }
})();

No, you should not create a global variable (and not with let anyway).
Yes, you should declare it outside of the function if you want to have it shared between calls.

You can use a closure for that, with any kind of module pattern - from ES6 module to IIFE to simple block scope.

// 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`
  };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM