Вернемся к основам с переменными и областью видимости

(Привет! Если вы цените содержание, которое я пишу, я был бы очень признателен, если бы вы подумали о том, чтобы стать участником Medium через мою реферальную ссылку. Теперь о том, для чего вы пришли сюда…)

В предыдущем посте я обсуждал некоторые различия между var, let и const.

В этом посте мы подробнее расскажем о различиях между ними. Так что держитесь за свои консоли!

Различия между let и var

Переменную var можно повторно объявить и обновить.

Переменная let должна быть обновлена, но не объявлена ​​повторно.

An example of trying to redeclare a let variable:
// In editor:
<script>
let points = 50;
let points = 60;
</script>
// In the console I get an error:
Uncaught SyntaxError: Identifier 'points' has already been declared

Однако я могу его обновить:

let points = 50;
points = 60;
// In console:
points
// Returns:
60

Сфера аренды

Если я объявлю переменную let в глобальной области видимости, а затем повторно объявлю ее в блоке (фигурные скобки), как в приведенном ниже примере, я не получу сообщения об ошибке в консоли, но фактически повторно объявить let не будет.

let points = 50;
let winner = false;
if(points > 40) {
  let winner = true;
}
// If I call:
winner
// It returns the first value: 
false

Почему это происходит?

Поскольку let winner = false и let winner = true на самом деле являются двумя отдельными переменными, потому что они имеют разную область видимости, даже если у них одно и то же имя. Для пояснения:

// This 'let' is scoped to the window (globally):
let winner = false;
if(points > 40) {
// This 'let' is scoped to the block (between the curly brackets):
  let winner = true;
}

В приведенном выше примере, если мы изменим bothletvariables на var, а затем вызовем winner в консоли, он вернет true, потому что он не внутри функции. (Помните: var имеет область видимости функции.) Переменная var повторно объявляется в пределах своей области видимости, которой в данном случае является окно.

let points = 50;
var winner = false;
if(points > 40) {
  var winner = true;
}
// If I call:
winner
// It now returns: 
true

Различия между let и const

const переменные не могут быть обновлены. let переменные сделаны для обновления.

// If I define the const variable:
const key = 'xyz123';
// Then try to redeclare it:
key = 'xyz1234'
// I get the following error:
Uncaught TypeError: Assignment to constant variable.

Однако есть интересная оговорка. Если я создаю const переменную, которая является объектом, атрибуты этого объекта могут быть обновлены.

// Creating my person object:
const person = {
  name: 'Joseph',
  age: 33
}
// Calling person in the console:
person
// It returns:
{name: "Joseph", age: 33}
// If I then redeclare the age attribute:
person.age = 34
// When I call it:
person
// It returns:
{name: "Joseph", age: 34}

Примечание. Если я хочу сделать объект неизменяемым, я могу «заморозить» его:

const joseph = Object.freeze(person);

Если я затем попытаюсь изменить атрибут объекта person в своей консоли, изменения не будут внесены:

// If I call:
person
// It returns:
{name: "Joseph", age: 33}
// However, if the object has been 'frozen' and I try to change the age attribute:
person.age = 34
// It will immediately return:
34
// But then when I call it:
person.age
// It returns the original age:
33

Преимущества использования let vs. var в цикле for

Я столкнулся со многими проблемами, связанными с областью видимости с циклами for при определении i с помощью var. Вот где использование let может оказаться выгодным.

// Running a for loop with var:
for(var i = 0; i < 10; i++){
    console.log(i);
}
// Returns 0 through 9 in the console, but if I call:
i
// It returns:
10

Другими словами, i просочился из области видимости цикла for и теперь может быть вызван в глобальной области (или любой другой родительской области)!

Другая проблема с использованием var в цикле for - это когда вы хотите сделать что-то в рамках цикла, но после цикл запускается. i объявляется заново каждый раз при запуске цикла.

// Do something one second after the loop runs:
for(var i = 0; i < 10; i++) {
    console.log(i);
    setTimeout(function() {
      console.log('The number is ' + i);
    }, 1000);
}
// If we then call i in the console it returns:
10

Опять же, переменная i перезаписывается каждый раз при запуске цикла. К моменту выполнения setTimeout i будет 10.

Быстрый способ исправить это - изменить var на let. Поскольку let привязан к блоку (в фигурных скобках), он будет вести себя по-другому и не будет переназначать i каждый раз при запуске цикла:

for(let i = 0; i < 10; i++) {
    console.log(i);
    setTimeout(function() {
      console.log('The number is ' + i);
    }, 1000);
}
// This returns 0 through 9 in the console, then after one second logs:
The number is 0
The number is 1
The number is 2
The number is 3
The number is 4
The number is 5
The number is 6
The number is 7
The number is 8
The number is 9