November 1, 2021

var, let, const: в чем разница?

Сегодня мы поговорим о важной теме, которую необходимо знать разработчику JavaScript. Каждый день вы используете var, let или/и const, но знаете ли вы разницу между ними. Об этом сегодня мы и поговорим.

var

Оператор var в наше время используется все реже, но это не значит, что его использование вредно.
На самом деле есть несколько хитростей, которые могут сделать код менее предсказуемым.

Переприсваивание

В переменную, объявленную через var, можно присвоить другое значение:

var myVariable = "First value";

myVariable = "Second value";
*Примечание: Вы не обязаны инициализировать значением:
var notInitializedVar;

Объявление var с одинаковым именем

Вы можете объявить несколько переменных с одинаковым именем:

var redeclaredVar = 'Первое объявление';

var redeclaredVar = 'Второе объявление';

Область видимостиvar

Область использования var зависит от того, где она объявлена.

В функции

Когда var объявлен внутри функции, его областью видимости будет вся функция. Если вы объявили переменную с помощью var внутри if, переменная будет доступна и за пределами if:

function myDummyFunction() {
  if (true) {
    var myVariable = "Переменная, объявленная с помощью var";
  }

  console.log(myVariable);
}
// Вывод "Переменная, объявленная с помощью var"
myDummyFunction();
Примечание: Переменная, конечно же также доступна во внутренних "блоках":
function myDummyFunction() {
  var myVariable = "Переменная, объявленная с помощью var";

  if (true) {
    console.log(myVariable);
  }
}
// Вывод "Переменная, объявленная с помощью var"
myDummyFunction();

За пределами функции

Когда мы объявляем переменную с помощью var вне функции, переменная будет глобальной переменной.

Например, если вы наберете в отладчике вашего браузера:

var myGlobalVariable = "Привет, я буду доступен в этом окне";
// Выведет "Привет, я буду доступен в этом окне".
console.log(window.myGlobalVariable);
Предупреждение: При работе с модулями ES и модулями commonJS эта переменная будет привязана только к модулю.
Примечание: Для того и создано Немедленно Вызванное Функциональное Выражение (Immediately Invoked Function Expressio - IIFE), чтобы переменная не находилась в глобальной области видимости и не конфликтовала с переменными других библиотек.

Hoisting (Поднятие)

Во-первых, давайте определим, что такое поднятие: это поведение, позволяющее автоматически помещать переменную или функцию в начало файла.
Благодаря поднятию, вы можете объявить свою функцию (стандартно объявленную, Function Declaration) после ее использования:

hoistedFunction();

function hoistedFunction() {
  console.log("Меня могут вызвать до моего объявления.");
}

Особенность var заключается в том, что переменная располагается в начале файла или функции (если она объявлена внутри функции) и инициализируется значением undefined.

// Будет выведено "undefined"
console.log(myHoistedVar);

var myHoistedVar = "Я - hoisted и инициализированный var";
function myDummyFunction() {
  
// Переменная объявлена внутри if, но условие в if всегда ложно
  console.log(myVariable);

  if (false) {
    var myVariable = "Переменная, объявленная с помощью var";
  }
}

// Будет выведено "undefined"
myDummyFunction();

Назначение неквалифицированного идентификатора

В нестрогом режиме (без "use strict";), если вы объявили переменную только с ее меткой и без классификатора (var, let или const), она будет автоматически создана какvar:

unqualifiedVar = "Я буду автоматически проходить квалификацию с var в нестрогом режиме";

//Это будет трансформировано в
var unqualifiedVar = "Я буду автоматически проходить квалификацию с var в нестрогом режиме";

Предупреждение: В строгом режиме это не будет работать и вызовет ошибку ReferenceError.

"use strict";

// В консоли вы увидите что-то вроде:
// Uncaught ReferenceError: unqualifiedVar не определена
unqualifiedVar = "Вызовет ошибку ReferenceError";

let

В повседневной жизни вы, вероятно, чаще используете переменную let, чем var. Но давайте освежим наши знания об этой переменной:

Переназначение

Как и var, вы можете переприсвоить значение в переменную, объявленную с помощью let:

let myVariable = "First value";

myVariable = "Second value";

Область видимостиlet

Здесь кроется одно из главных отличий от var. Переменная, определенная с помощью let, будет блочной (т.е. будет доступна только внутри текущей родительской фигурной скобки).

function myDummyFunction() {
  let myVariable = "Переменная let";

  if (true) {
    console.log(myVariable);
  }
}

// Будет выведено: Переменная let
myDummyFunction();

В отличие от var, она вызовет ошибку ReferenceError, если вы попытаетесь обратиться к переменной, объявленной во внутреннем блоке:

function myDummyFunction() {
  if (true) {
    let myVariable = "Переменная let";
  }

  console.log(myVariable);
}

// В консоли вы увидите что-то вроде
// Uncaught ReferenceError: myVariable не определена
myDummyFunction();

Примечание: Переменная, объявленная с помощью let, никогда не будет глобальной.

Нельзя пересоздавать одну и ту же переменную

В отличие от var вы не можете создать другую переменную с тем же именем. В противном случае, в консоли появится SyntaxError.

let myLetVariable = "Первое значение";

// В консоли вы увидите что-то вроде
// Uncaught SyntaxError: Идентификатор 'myLetVariable' уже был объявлен
let myLetVariable = "Второе значение";

А как насчет hoisting?

Переменная, созданная с помощью let (как и const), на самом деле также поднимается наверх, как и var, однако, пока мы не дойдем до создания переменной в коде, эта переменная будет находиться во временной мертвой зоне (Temporal Dead Zone или TDZ)
Пока переменная не инициализирована, при попытке обращения к ней будет возникать ошибка ReferenceError.

console.log(myLetVariable);

// В консоли вы увидите что-то вроде
// Uncaught ReferenceError: myLetVariable не определена
let myLetVariable = "Некоторое значение";

// Отсюда больше никаких TDZ

Такое поведение называется Временная мертвая зона (TDZ).

Если вы спросите, почему используется термин "временная"?
На самом деле это потому, что все зависит от того, когда выполняется код. Например:

setTimeout(() => console.log(myLetVariable), 500);

let myLetVariable = "Некоторое значение";

// Через 500 мс вы увидите
// "Некоторое значение" выводится в консоль

const

Переменная, объявленная с помощью const, имеет очень похожие свойства, что и let. Единственное различие заключается в переприсваивании в переменную и инициализации.

Нет переприсваивания

При использовании переменной, объявленной с const, невозможно присвоить в эту переменную другое значение:

const myConstVariable = "Первое значение";

// В консоли вы увидите что-то вроде
// Uncaught TypeError: Присвоение постоянной переменной
myConstVariable = "Второе значение";
Предупреждение: Переменная, объявленная с const, является изменяемой:
const person = {};

// Здесь происходит мутация
person.firstName = "Роман";

Инициализация

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

// В консоли вы увидите что-то вроде
// Uncaught SyntaxError: Отсутствующий инициализатор в объявлении const
const uninitializedConst;

Заключение

Надеюсь, в вашей голове все прояснилось. Если вам нужно что-то запомнить, я думаю, это будет то, что область видимости между var и let/const различна.
var имеет область видимости функции, когда объявлена внутри функции, и глобальную область видимости, когда вне ее. let и const имеют область видимости блока.
Переменная let/var может быть переприсвоена, в отличие от const. Но будьте внимательны, переменная, объявленная с const, не является неизменяемой.
Все три переменные являются hoisted, но var инициализируется в undefined, "всплывая наверх", в отличие от let и const, которые этого не делают.

Источник: https://dev.to/romaintrotard/var-let-const-what-s-the-difference-2eh0