When to use var, let and const in Javascript [translation of the article by Tyler McGinnis]

Hi, Habr! I present to you the translation of the article “var vs let vs const in JavaScript” by Tyler McGinnis.

image

In this article you will learn 2 new ways to create variables in Javascript (ES6), let and const. Throughout this article, we will look at the difference between var , let and const , as well as related topics such as: “function scope versus block scope”, “raising” of variables, and immunity.

If you prefer a video, watch this (original in English):


ES2015 (or ES6) introduced us to 2 new ways to create variables, let and const . But before we delve into the differences between var , let and const , there are some topics that you should learn first. These are the declaration of variables and their initialization, the scope (a particular scope of the function) and “elevation”.

Variable declaration and initialization


Variable declaration introduces a new identifier.

var declaration

Above, we create a new identifier which we call the “declaration”. In Javascript, when created, variables are initialized with the value undefined . This means that if we try to bring our variable declaration , we get undefined The .

var declaration
console.log(declaration)

And so, we deduced a variable declaration and we received undefined .

Compared to declaring a variable, initializing a variable is when you first set the value of this variable.

var declaration
console.log(declaration) // undefined
declaration = 'Это инициализация переменной'

And so, here we initialized the variable declaration by writing a string to it.

This leads us to the next concept, scope.

Area of ​​visibility


Scope characterizes where variables and functions can be accessed within our program. In Javascript, there are 2 types of scopes - a  global scope , and a function scope . According to the official specification,
“If a variable declaration occurs inside a function declaration, the variable is defined in the local scope of this function ...”
This means that if you create a variable with var , the scope of this variable will be the function in which it was created and will only be available inside this function or any other nested function.

functiongetDate () {
  var date = newDate()
  return date
}
getDate()
console.log(date) // NOT OK: Reference Error

Above, we tried to access the variable outside the function in which it was declared. Since the scope of the date variable is the getDate function , it is available only inside this function or in any other function nested in getDate (as shown below).

functiongetDate () {
  var date = newDate()
  functionformatDate () {
    return date.toDateString().slice(4) // OK
  }
  return formatDate()
}
getDate()
console.log(date) // NOT OK: Reference Error

Now let's take a look at a more advanced example. Let's say we have an array of prices and we need a function that accepts this array, as well as a discount variable , and returns us a new array of prices with discounts. The ultimate goal might look something like this:

discountPrices([100, 200, 300], .5)

And the implementation might look something like this:

functiondiscountPrices (prices, discount) {
  var discounted = []
  for (var i = 0; i < prices.length; i++) {
    var discountedPrice = prices[i] * (1 - discount)
    var finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  return discounted
}

It looks simple enough, but what does this have to do with the scope of the block? Take a look at this for loop . Are variables declared inside it available outside of it? It turns out available.

functiondiscountPrices (prices, discount) {
  var discounted = []
  for (var i = 0; i < prices.length; i++) {
    var discountedPrice = prices[i] * (1 - discount)
    var finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  console.log(i) // 3console.log(discountedPrice) // 150console.log(finalPrice) // 150return discounted
}

If JavaScript is the only programming language that you know, you can not worry about it. However, if you come to JavaScript from another programming language, in particular a programming language that blocks visibility, you are probably a little concerned about what is happening here.

It is not broken, it just works a little weird. There is really no reason to access i , discountPrice and finalPrice outside of the for loop . It does not do us any good and can even harm us in some situations. However, since variables are declared using var , they are included in the scope of the function and you can access them.

Now we have discussed the declaration and initialization of variables, as well as scopes, another thing we need to figure out before we dive into the analysis of the differences between let and const , this is “elevation”.

“Raising”


Remember, earlier it was said “In Javascript, when created, variables are initialized with the value undefined“. It turns out that it means “lifting”. The JavaScript interpreter sets declared variables to undefined during the phase called “Creation”.

For a more detailed look at the creation, elevation, and scope areas, read this article: “The Ultimate Guide to Hoisting, Scoping, and Closures in JavaScript .

Let's take a look at the previous example and see how “raising” affects it.

functiondiscountPrices (prices, discount) {
  var discounted = undefinedvar i = undefinedvar discountedPrice = undefinedvar finalPrice = undefined
  discounted = []
  for (var i = 0; i < prices.length; i++) {
    discountedPrice = prices[i] * (1 - discount)
    finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  console.log(i) // 3console.log(discountedPrice) // 150console.log(finalPrice) // 150return discounted
}

Note that all declared variables have been set to undefined . That's why if you try to access one of them before it is actually declared, you just get undefined .

functiondiscountPrices (prices, discount) {
  console.log(discounted) // undefinedvar discounted = []
  for (var i = 0; i < prices.length; i++) {
    var discountedPrice = prices[i] * (1 - discount)
    var finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  console.log(i) // 3console.log(discountedPrice) // 150console.log(finalPrice) // 150return discounted
}

Now you know everything you need about var , now let's finally talk about the main goal, because of which we are here: what is the difference between var , let and const ?

var, let or const


First, let's compare var and let . The key difference between var and let is that let, in addition to the global scope and function scope, allows variables in the scope of a block to be defined. This means that a variable created using the let keyword is available inside the “block” where it was created, also inside nested blocks. When I say "block", I mean anything surrounded by curly braces {}, for example, the cycle for operator or the if .

And so, let's go back to our discountPrices function for the last time.

functiondiscountPrices (prices, discount) {
  var discounted = []
  for (var i = 0; i < prices.length; i++) {
    var discountedPrice = prices[i] * (1 - discount)
    var finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  console.log(i) // 3console.log(discountedPrice) // 150console.log(finalPrice) // 150return discounted
}

Recall that we have the right to output i , discountPrice , and finalPrice outside of the for loop , since they were declared with var , and variables declared with the var keyword are limited to the scope of the function. But what happens now if we change var to let and try to run our code?

functiondiscountPrices (prices, discount) {
  let discounted = []
  for (let i = 0; i < prices.length; i++) {
    let discountedPrice = prices[i] * (1 - discount)
    let finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  console.log(i) // 3console.log(discountedPrice) // 150console.log(finalPrice) // 150return discounted
}
discountPrices([100, 200, 300], .5) // NOT OK: ReferenceError: i is not defined

We received ReferenceError: i is not defined . This tells us that a variable declared with let is limited to the scope of the block, not the function. Try to contact i (or discountedPrice or finalPrice ) outside the “block” where they were declared, and this will give us a conversion error, as we just saw.

var VS letvar: ограничена областью видимости функции
let: ограничена областью видимости блока

The following difference is due to “uplift”. Earlier, we said that the definition of “raising” is: “The JavaScript interpreter assigns undefined to declared variables during a phase called“ Creating ”.” We also saw this in action by calling the variable before declaring it (you got undefined ).

functiondiscountPrices (prices, discount) {
  console.log(discounted) // undefinedvar discounted = []
  for (var i = 0; i < prices.length; i++) {
    var discountedPrice = prices[i] * (1 - discount)
    var finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  console.log(i) // 3console.log(discountedPrice) // 150console.log(finalPrice) // 150return discounted
}

I can’t remember a single use case where you actually would like to access a variable before it is declared. It seems that getting a ReferenceError would be better than getting undefined .

In fact, this is what let does . If you try to access a variable before declaring it with let , instead of getting undefined (as was the case when declaring with var ), you will get a ReferenceError .

functiondiscountPrices (prices, discount) {
  console.log(discounted) // NOT OK: ReferenceErrorlet discounted = []
  for (let i = 0; i < prices.length; i++) {
    let discountedPrice = prices[i] * (1 - discount)
    let finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }
  console.log(i) // 3console.log(discountedPrice) // 150console.log(finalPrice) // 150return discounted
}

var VS letvar:
  ограничена областью видимости функции
  её значение будет undefined если вы попытаетесь обратиться к ней до её объявления.
let:
  ограничена областью видимости блока
  вы получите ReferenceError если попытаетесь обратиться к ней до её объявления.

let or const


Now you understand the difference between var and let, what about const? It turns out that const is almost the same as let. However, there is one difference: if you once assigned a value using const, you cannot change it to another.

let name = 'Tyler'const handle = 'tylermcginnis'
name = 'Tyler McGinnis'// OK
handle = '@tylermcginnis'// NOT OK: TypeError: Assignment to constant variable.

The conclusion from the fact that the above - variables declared with let can be overwritten, and variables declared with const can not.

Great, now when you want your variable to be unchanged, you can declare it with const . Or not at all. Just because a variable was declared with const does not mean that it is immutable, all that it means is that it cannot be overwritten. Below is a good example.

const person = {
  name: 'Kim Kardashian'
}
person.name = 'Kim Kardashian West'// OK
person = {} // NOT OK: Assignment to constant variable.

Note that changing an object's property is not its rewriting, so even if an object is declared with const , this does not mean that you cannot change any of its properties. It only means that you cannot overwrite this object.

Now, the most important question that has not yet been answered is: what should var , let or const be used for ? The most popular opinion, and the opinion of which I hold, is to always use const , as long as you do not know whether the variable will change. The reason for this is that using constyou are making it clear to yourself and future developers who need to read your code that this variable should not be changed. If you need to change it (for example, in a for loop ), just use let .

Between variables that change and variables that do not change, there are not too many cases left. This means that you will never need to use var again .

Now an unpopular opinion, although it still has a rationale, is that you should never use const , despite the fact that you are trying to show that this variable is constant, as we saw above, this is not exactly the case. Developers who hold this opinion always use letthere are no variables that are actually constants, such as _LOCATION_ = ....

We will summarize the above, var is limited to the scope of the function, and if you try to access such a variable before its declaration, you will get undefined . const and let are limited to the block's scope and if you try to access these variables before they are declared, you will get a ReferenceError . And the difference between const and let is that the value that was assigned to const cannot be overwritten, unlike let .

var VS let VS constvar:
  ограничена областью видимости функции
  её значение будет undefined если вы попытаетесь обратиться к ней до её объявления.
let:
  ограничена областью видимости блока
  вы получите ReferenceError если попытаетесь обратиться к ней до её объявления.
const:
  ограничена областью видимости блока
  вы получите ReferenceError если попытаетесь обратиться к ней до её объявления.
 не может быть перезаписана

This article was originally published on tylermcginnis.com as part of the Modern JavaScript course.

Thank you for reading this translation, I hope you have come to know something new and useful for yourself. I would be happy to see feedback!

Also popular now: