Добро пожаловать в TIE: сегодня я объясняю. Это вторая часть серии статей о ключевых концепциях JavaScript, которые помогают разработчикам js стать лучшими разработчиками js. Найдите первую часть здесь.

Краткая заметка: я начинаю с нескольких основ. Мой стиль разговорный. Я углублюсь в более глубокие вещи в течение жизни этого блога. Если вы супер-продвинутый, пожалуйста, не стесняйтесь оставлять знания в комментариях. Если я ошибся, отзовитесь!

Также, если кому-то интересно, откуда взялся заголовок этого поста, ответ — да.

Сегодня мы говорим о переменных ES6, подъеме, скоупах и немного изменчивости.

В Javascript мы объявляем переменные, используя следующие ключевые слова:

var
let
const

Ключевое слово var может быть знакомо большинству. let и const были введены, когда появился ES6. До этого var была единственной игрой в городе. Возможно, вам говорили, что var и let взаимозаменяемы. Они не.

Итак, давайте поговорим о подъеме.

Подъем с помощью var

При использовании var объявления переменных поднимаются наверх своей области видимости. Рассмотрим следующие примеры:

// EXAMPLE 1
console.log(puppy);
var puppy = "Pancake";
console.log(puppy);
// is the same as
var puppy;
console.log(puppy);
var puppy = "Pancake";
console.log(puppy);

В первом примере var Puppy = «Pancake»; — это выражение. Выражение не поднимается в начало области видимости. Вы знаете, что поднято, хотя? Объявление переменной! Если у вас возникли проблемы с объявлениями и выражениями, вы можете потренироваться переписывать их в уме (как во втором разделе примера 1), пока вам больше не понадобятся тренировочные колеса.

Какие отпечатки?

Если бы вы сказали «неопределенный» и «блин», вы были бы правы! При первом вызове console.log машина знает только varpup, которому еще не присвоено значение. При втором вызове console.log нашей переменной было присвоено значение «Pancake», и поэтому машина печатает «Pancake».

Ура!

Ладно, просто для забавы, быстрый обзор прицелов. Что здесь происходит?

// EXAMPLE 2
console.log(puppy);
let puppies = () => {
  console.log(puppy);
  var puppy = "Pancake";
  console.log(puppy);
}

Ах!

ReferenceError: puppy is not defined

Этот первый console.log в глобальной области видимости не имеет доступа к переменным в функции щенков. Если мы закомментируем эту первую строку, машина напечатает «undefined» и «Pancake», как мы и ожидали.

Итак, теперь мы понимаем, как работает подъем с var.

В таком случае, если мы заменим var на let, результат будет таким же. Поэтому иногда говорят, что они взаимозаменяемы. Конечно, в данном случае они есть. Но продолжайте читать.

Области с пусть

// EXAMPLE 1 WITH VAR
for (var i = 0; i < 5; i++) {
  setTimeout(function() { console.log(i); }, i * 1000 );
}
// prints 5, 5, 5, 5, 5

// EXAMPLE 2 WITH LET
for (let i = 0; i < 5; i++) {
  setTimeout(function() { console.log(i); }, i * 1000 );
}
// prints 0, 1, 2, 3, 4

В первом примере, где используется var, каждая функция внутри цикла выполняется только после завершения цикла. Здесь var i — это одна переменная, и функция в setTimeout ссылается на эту переменную. Когда цикл завершится, var i всегда будет равно 5. Запутались? Проверь это.

// var i; <-- invisible but it's there
for (var i = 0; i < 5; i++) {
  setTimeout(function() { console.log(i); }, i * 1000 );
}
console.log(i); // logs 5;

С помощью var объявления поднимаются вверх. В приведенном выше примере есть невидимая var i перед циклом for. Опять же, каждый раз при выполнении цикла var i = 5. Функция внутри цикла for ссылается на var i, поэтому она выводит 5.

Во втором примере это тот же код, но мы используем let. Это крошечное обновление ES6 выводит совершенно другой ответ. Рассмотрим этот код:

for (let i = 0; i < 5; i++) {
  setTimeout(function() { console.log(i); }, i * 1000 );
}
console.log(i); // ReferenceError: i is not defined

С let перед циклом for нет объявления невидимой переменной. Декларации не поднимаются наверх! Когда мы пытаемся выполнить console.log вне цикла for, мы получаем ошибку ссылки, потому что машине не на что ссылаться.

Почему это важно? Это важно, потому что let имеет область действия блока, а var игнорирует область действия блока. let i недоступен за пределами области действия блока, которой в данном случае является цикл for. Здесь let i определен в пределах области блока и не распространяется на глобальную область действия, как это делает var.

В результате let i действует по-другому. По мере повторения цикла пусть i = 0 печатается 0. Затем пусть i = 1 печатается 1. И так далее.

Хорошо, теперь запустите это:

for (const i = 0; i < 5; i++) {
  setTimeout(function() { console.log(i); }, i * 1000 );
}

Грубый.

Изменчивость

Const неизменен. Это означает, что он неизменен. Если вы присвоите const значение, вы не сможете переназначить его позже.

const northernStar = "Polaris";
northernStar = "Betelgeuse"; 
console.log(northernStar);
// SyntaxError: Assignment to constant variable: northernStar
let northernStar = "Polaris";
northernStar = "Betelgeuse"; 
console.log(northernStar); // "Betelgeuse"
var northernStar = "Polaris";
northernStar = "Betelgeuse"; 
console.log(northernStar); // "Betelgeuse"

Однако в типичном стиле JavaScript const не является полностью неизменным. Вы можете изменить его свойства.

const outfit = {pants: 'maybe'};
outfit.pants = 'not today';
console.log(outfit) // { pants: 'not today' }