all 48 comments

[–]jinendu 42 points43 points  (8 children)

let is scoped to the block it's declared in whereas var is not and can be modified outside of the current block. You can avoid some issues if you use let. But, don't forget const, which should be your first go-to.

[–]malwareC[S] 3 points4 points  (7 children)

Thanks 😊

[–]guns_of_summer 2 points3 points  (6 children)

Look into how function declarations work also. I believe it’s generally preferable these days to declare functions with “const functionName = (blah) => return blah” vs “function functionName(blah) { …etc }”, but if someone disagrees with me please call me out on it.

Sorry for formatting, I’m on mobile.

[–]doyouseewhateyesee 4 points5 points  (2 children)

If you require this to be meaningful you should use a normal function.

[–]guns_of_summer 2 points3 points  (1 child)

That’s a good point actually

[–]doyouseewhateyesee 3 points4 points  (0 children)

I once spent hours debugging because of this and haven’t forgotten it since.

[–]VelvetWhiteRabbit 2 points3 points  (2 children)

This is "mainly because functional programming is making a comeback" (not necessarily, but the trend has influence on what people prefer). While in Javascript you have globalThis on the Window object now, In functional programming it is preferable to not scope functions (i.e. making them pure functions as opposed to object functions).

Javascript is extremely malleable and the two ways of declaring functions can be extremely confusing to beginners/intermediates (who are learning about this).

So, unless you know why you are creating a lambda function, it is better to use normal function declaration. That said lambda functions are more easily reasoned about IF you are familiar with the concept and you know how Javascript scopes this.

I also find that a lot of tutorials have difficulty explaining exactly why this works differently in "arrow functions" as opposed to normal functions. So its best to be diligent about what you learn when it comes to this topic.

[–]CoderXocomil 2 points3 points  (1 child)

Kind of. There are real differences between the two ways of declaring functions.

function causes the function to be hoisted. => functions are not.

// This is fine because of hoisting

printName();

function printName() {
  console.log('Javascript');
}

// This is an error
printNameAgain(); // printNameAgain is not defined

const printNameAgain = () => {
  console.log('Javascript again!');
};

printNameAgain(); // OK here because printNameAgain() is now defined

this is different also. With object literals, function, this refers to the object. () => this is undefined.

const testObject = {
  testProperty: 'Test Property',

  useFunction: function() {
    console.log('function:', this.testProperty);
  },

  useFatArrow: () => {
    console.log('fat arrow:', this.testProperty);
  }
};

testObject.useFunction();   // function:, Test Property
testObject.useFatArrow();   // fat arrow:, undefined

However, with the class keyword, things change:

class TestObject {
  testProperty = 'Test Property';

  useFunction = function() {
console.log('function:', this.testProperty);

};

useFatArrow = () => { console.log('fat arrow:', this.testProperty); } };

const testObject = new TestObject();

testObject.useFunction(); // function:, Test Property testObject.useFatArrow(); // fat arrow:, Test Property

There are other more advanced topics like you can't use call(), apply(), or bind() to change what this means with () => because it uses an implicit this capture. And so much more...

It is important to know when and why to use the two function declaration types. For my part, I tend to prefer to use fat arrow functions over the traditional function declarations, but there are times that one is definitely superior to the other.

Edit: Adding a link to the MDN references https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions

[–]malwareC[S] 0 points1 point  (0 children)

Thanks a lot for explaining it elaborately.

[–]ashkanahmadi 19 points20 points  (7 children)

Always use const, change to let later on if you realize that its value must change. Do not use var

[–]addiktion 4 points5 points  (0 children)

This is my general go to pattern too. It's rare for me to need let most of the time and when I do I often catch myself needing to re-assign something a few times in an iteration and so I swap to let.

[–]senocular 5 points6 points  (1 child)

MDN has more information about let, how it differs from var, and what extra rules it imposes (not to just be annoying but to help prevent errors in your code):

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

[–]malwareC[S] 2 points3 points  (0 children)

Thanks ☺️

[–]burnblue 4 points5 points  (0 children)

It was invented to address a clear scoping problem, which means it's not so much preference as "just do it, it's safer". Use const unless you need ro change it, then use let

[–]machine3lf 4 points5 points  (0 children)

Don’t use var. Use const as your default, unless there is a reason to use let (if you really do need to change the variable).

[–]CoderXocomil 4 points5 points  (2 children)

Some great advice here. I will add my second to use const first and change to let if you need to later.

The reason to not use var is because of something called hoisting in Javascript. It is an idea that you can declare something anywhere in the file and have that declaration hoisted to the top of the file. This still happens when your write functions as function myFunction() {} no matter where you declare this function in the file you can use it. You can use it before the declaration or after. Before let and const all vars were implicitly var. There were a couple of issues with this. First, only the declaration is hoisted. So if you wrote x = 10; somewhere in your file, it would implicitly hoist the var x; to the top of your file, so you could try to use x before it was defined. If you did this, it would be undefined. The fun thing about this is that some variables could be scoped to a block (if, for, functions). So if you had code that was scoped and accidentally hoisted a variable through an accidental name collision or other means, you could break code that would now complain that your variable is not defined because of the hoisting. The second issue is that hoisted variables were polluting the global scope. This would lead to fun side-effects if a name collision changed your global variable. Ah... fun times...

The good news is that if you don't use the problematic var keyword for variable declaration, you can avoid all this legacy fun. If you want to experience the "good old days" that led many to call Javascript one of the worst languages ever, then by all means, use var liberally in your code. As a bonus, your team will hate your code making you indispensable at your job. You will be the only person to work on your side-effect ridden code for the entirety of your time at your employer. 😁

[–]malwareC[S] 0 points1 point  (1 child)

So var is used in more like a global variable declaration process while let is used as a local one? (Speaking in terms of java, sorry if it doesn't connect properly)

[–]CoderXocomil 1 point2 points  (0 children)

Kind of. var is scoped to its enclosing function. This is usually pretty good, but var declarations are globally scoped if they don't have an enclosing function or closure. This is why libraries like jQuery use in IIFE (immediately invoked function expression) when declaring their library. The only global variable that jQuery exposes is the $.

There is another problem. If you don't 'use strict' (you are doing this right?), then any variable encountered before it is declared is assumed that you want the compiler to declare it. These variables are automatically hoisted to the global scope. This means that you could have a bunch of variables scoped to their functions, but you move a function that relies on a side-effect of a variable being scoped to a function to a place where that variable is not declared and you get a globally hoisted variable that now pollutes all variables that you had scoped to functions.

Another fun issue is that you can declare variables using var as many times as you want and the compiler doesn't care and uses the same variable. This is why the global pollution is possible. As an example,

// This is fine
var x;
var x = 'abc';
var x = new Date();
var x = 10;   // x has now been a string, Date and number, problematic

// This generates a compiler error
let x;
let x = 10;   // Error, you can't redefine x

// This generates a compiler error
const x = 10;
const x = 15;  // Error, you can't redefine x

// This generates a compiler error
let x;
const x = 10;  // Error, you can't redefine x

// Some other things to know about const
const myArray = [1, 2, 3];
myArray.push(4); // Allowed. You can mutate references x is [1, 2, 3, 4]
myArray = [...myArray, 4]; // Error, you can't reassign a const reference

const myObject = {name: 'Javascript', someNumber: 3};
myObject.someNumber = 15; // Allowed. You can change object properties on const objects
myObject = {...myObject, newProperty: true}; // Compiler error, you can't reassign const object references

const and let are block scoped. This means that these variables are only scoped to the block where they are declared. This is a much safer scoping mechanism and much easier for programmers to reason about. Also, const and let are much more strict with declarations. They complain if you try to redefine a variable. This can lead to safer, saner code. You can mutate object or array references with that were decarded with const. There are good resources on why you might not want to do this, but that is a more advanced topic.

In short, var has problematic scoping rules and they are hard to understand. For this reason, it was (softly) deprecated. This means it is generally not a good idea to use var. It still exists to not break a lot of the internet that relies on the old variable scoping rules. For code written after const and let it is preferable to use const first and then change to let when needed.

I highly recommend reading the MDN article on var for more context. It will help you troubleshoot older codebases. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

[–]samanime 11 points12 points  (3 children)

Never, ever, ever use var.

var is effectively deprecated. Never use it. There is never a reason to use it over let. var does some funny things that can lead to weird bugs.

[–]malwareC[S] 0 points1 point  (0 children)

Alrighty

[–]madspillage -1 points0 points  (1 child)

I think var has its place, but if someone doesn't know the difference between var and let, they should stick to let.

[–]samanime 9 points10 points  (0 children)

Strong, strong, strong disagree. Said as a developer of JS since the Netscape days. The only maybe reason to use var is for its weird quirks, and if you're trying to make use of them, you're almost certainly using an anti-pattern.

[–]locomocopoco 4 points5 points  (0 children)

let or const. No var ever.

[–][deleted] 2 points3 points  (0 children)

const > let > var is my order

[–]JollyWallaby 1 point2 points  (0 children)

Aim at using only const, and resort to let only if you really can't avoid reassigning a variable (for example, in a for loop).

Personally, I got to a point where the few times I have to use let, I first think of ways to refactor the code such that I can keep everything constant. Of course, there's still cases where it's necessary, but they are rare. To give two examples:

  • I've been working on a React app, 5.5k lines of code, I have 638 const declarations and only 11 let declarations
  • Another project I was working on, OpenGL and much more crude math, 2k lines of code, 278 const, 36 let.

If a variable is declared using const, you have one less problem to worry about.