4

I'll try to make this concise...

With all the ES6 hype, I feel like using the var keyword is becoming more and more frowned upon by the JS community at large. Due to this (perceived) general consensus, I've been getting in the habit of avoiding using var in lieu of the newer const and let keywords for creating variables.

Below is an example of a block of code I wrote where I couldn't use const because I wanted to redefine a variable. I was also using async / await so all the code was in the same block-level scope, which apparently prevents you from redefining let variables either. So my only option was to use var (or create yet another let variable).

Here's the code. Saving a new user account to a MongoDB via Mongoose...

router.post('/signup', async (req, res, next) => {
  const { email, password } = req.body;

  const user = await userModel.findOne({ email });
  if (user) { res.send('Email already in use.'); return; }

  // here is where the issue occurs - use var instead?
  let newUser = new userModel({ email, password });
  let newUser = await newUser.save();

  console.log(newUser); // just checking everything works

  res.send({ message: 'New user account created!' });
});

MDN mentions this behavior... with just ONE SENTENCE! That's not helpful. :( And then they go on to discuss hoisting behavior, which isn't my issue, or at least I don't see how that's related. MDN Source Here.

So in conclusion...

  • Is this an example of an instance when var would be the most appropriate keyword to use?

  • If this isn't a time for using var, is there any instance when var is the most appropriate keyword to use, even in the age of ES6 (7, 8, etc)?

Disclaimer: I know I don't absolutely need to save those variables, but in my opinion, it's worth the trade off to write slightly more verbose code that's also more readable and understandable. I'm fine with using var, I just though this was an interesting case.

TJBlackman
  • 1,895
  • 3
  • 20
  • 46
  • 1
    Why does this code block need to redefine a variable? I don't see it. You can "assign"' to a variable defined with `let` just fine. I know of no case where `var` is better than choosing the appropriate `let` or `const`. – jfriend00 May 03 '18 at 05:23
  • No, there not a single case where `var` should be used over `let` or `const`. You can reassign variable defined with `let` keyword in the same way you can do it with `var` defined variables. And there is never any good reason to redefine the same variable inside of the same scope (don't read reassign). – Matus Dubrava May 03 '18 at 05:34

3 Answers3

3

There is no reason to ever use var in ES6. const should be your default. The only reason to use let over const is when you want to reassign the variable later in the same block. In that case you don't declare it again, just assign the new value to it:

let newUser = new userModel({ email, password });
newUser = await newUser.save();
// allowed to reassign because `newUser` is not `const`

Depending on what save does, I suspect you could just do:

const newUser = new userModel({ email, password });
await newUser.save();

newUser.save(); should reject the Promise it returns if the save failed, which await will convert to a thrown error. So there should be no question about whether or not the save succeeded in the code after that await. If those lines are reached, the save succeeded.

Paul
  • 139,544
  • 27
  • 275
  • 264
  • There is no reason to ever use `var` in JavaScript, but `let` could be our default. ;) – Paleo May 03 '18 at 08:24
  • omg - I'm so dumb. Of course, this makes perfect sense. Thank you! Pretty much every one had great answers. – TJBlackman May 03 '18 at 12:15
  • @Paleo `let` is not a good default. When you read `const newUser = new userModel({ email, password });` it tells you exactly what `newUser` refers to for the rest of the block without needing any further scanning. `let newUser = new userModel({ email, password });` tells you what `newUser` ***might*** be for the rest of the block, but you need to scan the whole block to know for sure. Defaulting to `const` makes reading and writing better code easier and faster. – Paul May 03 '18 at 18:17
  • 1
    Reassigning in general should be avoided if possible and instead a new variable should be created (for the reason above). There are many scenarios where that is not possible and using `let` indicates that the variable is not immediately initialized to its final value. Usually that means it is a variable for some form of counting EG. `count`, `sum`, `product` iterators `i`,`j`,`k` or a variable whose final value is undetermined until more information becomes available later (maybe a variable that is assigned inside some callback function or inside a switch statement's cases). – Paul May 03 '18 at 18:29
  • 1
    `const` should be your default... How misleading... A **var**iable that can not be varied. – Redu May 03 '18 at 23:34
  • @Redu It's not misleading at all. The value of a variable declared `const` can vary. It just cant be modified after its initialized. `const x = Math.random();` declares a variable name `x` that can be one of many different values. Later expressions might operate on that, like `const isHeads = x < 0.5;`. Your statement only makes sense in a universe where any given line of code can only be evaluated once ever. – Paul May 03 '18 at 23:59
  • @Paulpro This is an opinion. The opposite opinion is explained here: [Use `let` by default, not `const`](https://thinkbig.blog/use-let-by-default-not-const-58773e53db52). – Paleo May 04 '18 at 09:20
  • I summarized the pros and cons of using `const` by default here: https://stackoverflow.com/a/50151917/3786294 – Paleo May 04 '18 at 10:47
  • @Paleo It's not an opinion. It's objectively better to use `const` by default. That blog post is full of opinions and strawman arguments. The only valid point that it brings up is "Inconsistencies with function parameters.", which I agree is a bug in the language that unfortunately needs to be kept for the language backwards compatible so that existing code doesn't break in newer versions. – Paul May 04 '18 at 17:01
  • @Paleo I'm confident that anyone who says using `let` is a better default hasn't tried using `const` as their default for a few days of coding. I was skeptical at first too after being used to `var` for so long, but after trying it I realized how much it speeds up development and reduces bugs. – Paul May 04 '18 at 17:03
1

This is not the matter of using let , var, or const.
Within the same scope a variable name cannot be declared more than one time, or you will get the following Error; SyntaxError: Identifier 'newUser' has already been declared
You can declare once and assign value as many as you want.
let newUser = new userModel({ email, password }); newUser = await newUser.save();

Sam Ho
  • 206
  • 1
  • 4
1

var usage is often restricted in linter rules because it's prone to be misused in ES6. This isn't a valid case for var. As another answer mentions, the variable should be reassigned, not redeclared:

  let newUser = new userModel({ email, password });
  newUser = await newUser.save();

The only valid case for var in ES6 is to define a global in top-level scope:

<script>var FOO = 1;</script>

let and const will result in Identifier has already been declared error if a variable was defined multiple times for some reason:

<script>let FOO = 1;</script>
...
<script>let FOO = 1;</script>

And if (typeof FOO === 'undefined) safeguard isn't applicable because it creates block scope.

This is applicable to browser scripts only. Node.js scripts are evaluated in module scope.

Alternatives may involve referring this (in loose mode) or window properties.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565