Присоединяйтесь к новому бесплатному курсу по Angular: "Список пользователей"
Курс проходит в мессенджере (Telegram, Viber). В конце курса - сессия живого разбора кода. Регистрация по ссылке.

30 Окт 2017

«Всплытиe» JavaScript переменных с использованием let и const

Начинающие JavaScript разработчики часто с трудом понимают уникальное поведение всплытия(hoisting) переменных и функций.
Поскольку мы будем говорить об объявление переменных var, let и const, важно понять что такое всплытие переменных. Давайте погрузимся!

Что же такое хоистинг переменных ?

Интерпретатор JavaScript всегда незаметно для нас перемещает («поднимает») объявления функций и переменных в начало области видимости.То есть переменные могут быть доступны до их объявления.

Давайте посмотрим на это в действии…


console.log(shape); // OUTPUT : undefined

var shape = "square";

console.log(shape); // OUTPUT : "square"

Если вы пришли из языков семейства С, вы будете ждать возникновение ошибки при вызове первого console.log, так как переменная не была определена непосредственно перед самим вызовом этого console.log. Но JavaScript интерпретатор смотрит вперед и поднимает все объявления переменных вверх, а их инициализация остается в том месте где они были объявлены по факту.

Вот что происходит за кулисами:


//Объявление поднялось вверх
var shape;
console.log(shape); // OUTPUT : undefined

var shape = "square";
console.log(shape); // OUTPUT : "square"

Для наглядности, другой пример, в этот раз в области видимости функции:


function getShape(condition) {
// здесь shape будет со значение
console.log(shape); // OUTPUT : undefined
if (condition) {
var shape = "blue";
// some other code
return shape;
} else {
// здесь shape будет со значение undefined
return false;
}
}

В примере выше вы можете увидеть как объявление переменной shape поднялось в начало тела функции getShape(). Поэтому наша переменная доступна за пределами блока if в области видимости функции со значение undefined.

Такое странное поведение в JavaScript имеет свои преимущества и недостатки. Непонимание этих особенностей может привести к появлению ошибок в вашем коде.

Объявление переменных на уровне блока!

В ES6 ввели область видимости на блочном уровне, что дало разработчикам возможность большего контроля над жизненным циклом переменных.Переменная, объявленная внутри блока, будет доступна только в области этого блока.

Объявление let.

Синтаксис объявления аналогичен с var, просто замените var на let, чтобы объявить переменную с ее областью, являющейся только этим блоком кода.

Разместите объявления переменных let в верхней части блока, чтобы они были доступны во всем блоке.

Например:


function getShape(condition) {
// shape doesn't exist here
// console.log(shape); => ReferenceError: shape is not defined
if (condition) {
let shape = "blue";
// some other code
return shape;
} else {
// shape doesn't exist here
return false;
}
}

Обратите внимание, что shape существует только внутри блока if и выдает ошибку при попытке доступе к ней за его пределами вместо вывода undefined, как в нашем предыдущем случае, с объявлениями var.

ПРИМЕЧАНИЕ: Если объявить переменную, и в одной области видимости с ней объявить такую же переменную let, то в результате мы увидим ошибку. Но если объявить такую же переменную let в другой области видимости, ошибки не будет.(Этот случай аналогичен объявлениям const, о которых мы поговорим в минутой позже.)

Например:


var shape = "square";
let shape = "rectangle";
// SyntaxError: Identifier 'shape' has already been declared

и:


var shape = "square";
if (condition) {
// не выдает ошибку
let shape = "rectangle";
}
// No error

Объявление const

Синтаксис объявления такой же как у let и var, жизненные цикл аналогичен let. Но есть некоторые отличия в поведение, которые вы должны знать.

Переменные, объявленные с использованием const, рассматриваются как константы, поэтому их значения не могут быть изменены после их определения. В связи с этим каждое объявление const должно быть инициализировано во время объявления.

Например:


// valid
const shape = "triangle";
const color; // syntax error: missing initialization
shape = "square" // TypeError: Assignment to constant variable

Однако это правило не постоянно и разниться, когда дело касается объектов. Значение объекта может быть изменено!


const shape = {
name: "triangle",
sides: 3
}
// WORKS
shape.name = "square";
shape.sides = 4;
// SyntaxError: Invalid shorthand property initializer
shape = {
name: "hexagon",
sides: 6
}

В приведенном выше примере мы можем видеть, что только свойства объекта shape могут быть изменены, потому что мы изменяем только вместимое объекта, а не то, к чему он привязан.

В целом ,мы можем сказать, что const предотвращает модификацию привязки в целом, а не значение, к которому она привязана.

Примечание: свойства могут быть изменены. Поэтому для истинной неизменности используйте Immutable.js или Mori.

Временная Мертвая Зона

Теперь мы знаем, что доступ к переменным let или const до их объявления будет вызывать ReferenceError. Этот период между вводом области и объявлением там, где они не могут быть доступны, называется временной мертвой зоной.

Имейте ввиду, что «Временная мертвая зона» официально не упоминается в спецификации ECMAScript. Это просто популярный термин среди программистов.

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

Я надеюсь эта статья помогла вам. Увидимся !