Переменные: let и const
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
В ES-2015 предусмотрены новые способы объявления переменных: через let и const вместо var .
let a = 5;
let
У объявлений переменной через let есть три основных отличия от var :
-
Область видимости переменной let – блок <. >. Как мы помним, переменная, объявленная через var , видна везде в функции. Переменная, объявленная через let , видна только в рамках блока <. >, в котором объявлена. Это, в частности, влияет на объявления внутри if , while или for . Например, переменная через var :
var apples = 5; if (true) < var apples = 10; alert(apples); // 10 (внутри блока) >alert(apples); // 10 (снаружи блока то же самое)
В примере выше apples – одна переменная на весь код, которая модифицируется в if . То же самое с let будет работать по-другому:
let apples = 5; // (*) if (true) < let apples = 10; alert(apples); // 10 (внутри блока) >alert(apples); // 5 (снаружи блока значение не изменилось)
Здесь, фактически, две независимые переменные apples , одна – глобальная, вторая – в блоке if . Заметим, что если объявление let apples в первой строке (*) удалить, то в последнем alert будет ошибка: переменная не определена:
if (true) < let apples = 10; alert(apples); // 10 (внутри блока) >alert(apples); // ошибка!
alert(a); // undefined var a = 5;
С переменными let всё проще. До объявления их вообще нет. Такой доступ приведёт к ошибке:
alert(a); // ошибка, нет такой переменной let a = 5;
Заметим также, что переменные let нельзя повторно объявлять. То есть, такой код выведет ошибку:
let x; let x; // ошибка: переменная x уже объявлена
Это – хоть и выглядит ограничением по сравнению с var , но на самом деле проблем не создаёт. Например, два таких цикла совсем не конфликтуют:
// каждый цикл имеет свою переменную i for(let i = 0; i for(let i = 0; i alert( i ); // ошибка: глобальной i нет
for(var i=0; i alert(i); // 10
С переменной let – всё по-другому. Каждому повторению цикла соответствует своя независимая переменная let . Если внутри цикла есть вложенные объявления функций, то в замыкании каждой будет та переменная, которая была при соответствующей итерации. Это позволяет легко решить классическую проблему с замыканиями, описанную в задаче Армия функций.
function makeArmy() < let shooters = []; for (let i = 0; i < 10; i++) < shooters.push(function() < alert( i ); // выводит свой номер >); > return shooters; > var army = makeArmy(); army[0](); // 0 army[5](); // 5
const
Объявление const задаёт константу, то есть переменную, которую нельзя менять:
const apple = 5; apple = 10; // ошибка
В остальном объявление const полностью аналогично let .
Заметим, что если в константу присвоен объект, то от изменения защищена сама константа, но не свойства внутри неё:
const user = < name: "Вася" >; user.name = "Петя"; // допустимо user = 5; // нельзя, будет ошибка
То же самое верно, если константе присвоен массив или другое объектное значение.
константы и КОНСТАНТЫ
Константы, которые жёстко заданы всегда, во время всей программы, обычно пишутся в верхнем регистре. Например: const ORANGE = «#ffa500» .
Большинство переменных – константы в другом смысле: они не меняются после присвоения. Но при разных запусках функции это значение может быть разным. Для таких переменных можно использовать const и обычные строчные буквы в имени.
Итого
- Видны только после объявления и только в текущем блоке.
- Нельзя переобъявлять (в том же блоке).
- При объявлении переменной в цикле for(let …) – она видна только в этом цикле. Причём каждой итерации соответствует своя переменная let .
Переменная const – это константа, в остальном – как let .
Переменные const , let и var
Чем отличаются const , let или var ? Рассказываем, что такое переменные и какими они бывают.
Время чтения: 9 мин
Открыть/закрыть навигацию по статье
- Кратко
- Что такое переменные
- Правила именования переменных
- Создание переменных
- Переменные let и const
- Объявление
- Одинаковые имена переменных
- Смена значения в let и const
- Объявление
- Смена значения в var
- Сергей Фомин советует
- В чём разница между null, undefined и объявленной переменной без начального значения? (let foo;)
- Разница между let, const и var?
Контрибьюторы:
Обновлено 14 ноября 2022
Кратко
Скопировать ссылку «Кратко» Скопировано
Переменные в JavaScript хранят значения, которыми оперирует код. Для создания переменных используются ключевые слова var , let и const .
Использование var оправданно, если нужно писать код для старых браузеров времён IE 11 или Opera mini. Во всех остальных случаях лучше использовать let и const , так как они не позволят допустить ошибки, приводящие к неправильным значениям в переменных или изменениям глобальных переменных.
Что такое переменные
Скопировать ссылку «Что такое переменные» Скопировано
Переменные — это именованные контейнеры для хранения данных.
Для создания переменной используется ключевое слово let , const или var . Сразу за ключевым словом идёт название переменной либо перечень переменных через запятую. Создание переменной также называют объявлением переменной. Например:
var singleVariable let firstVariable, secondVariable, thirdVariable
var singleVariable let firstVariable, secondVariable, thirdVariable
Чаще всего, при объявлении переменной ей устанавливают стартовое значение при помощи оператора присваивания = . Тип значения может быть абсолютно любым — строка, число, объект, массив и так далее.
// Объявление переменной и присваиваниеlet string = 'foo'const array = ['foo', 'bar', 'baz']var number = 10 // Множественное объявление и присваиваниеlet firstNumber = 5, secondNumber = 10
// Объявление переменной и присваивание let string = 'foo' const array = ['foo', 'bar', 'baz'] var number = 10 // Множественное объявление и присваивание let firstNumber = 5, secondNumber = 10
Затем переменную можно использовать как заменитель значения в коде:
let name = 'Уолтер'let surname = 'Вайт'let fullName = name + ' ' + surname console.log(fullName)// Уолтер Вайт
let name = 'Уолтер' let surname = 'Вайт' let fullName = name + ' ' + surname console.log(fullName) // Уолтер Вайт
Правила именования переменных
Скопировать ссылку «Правила именования переменных» Скопировано
Для имени переменной можно использовать следующие символы:
- буквы латинского алфавита;
- цифры;
- символы $ и _ .
Первый символ не должен быть цифрой:
let letters, $dollarsign, _underscore let 1number// SyntaxError: Invalid or unexpected token
let letters, $dollarsign, _underscore let 1number // SyntaxError: Invalid or unexpected token
В качестве названий переменных нельзя использовать зарезервированные языком слова. Например: class , super , throw , yield , var , let , const и так далее. С полным списком таких слов можно ознакомиться здесь.
Создание переменных
Скопировать ссылку «Создание переменных» Скопировано
Перед выполнением скрипта JavaScript находит код создания переменных и заранее создаёт их. Получается, что в начале выполнения скрипта все переменные, описанные в коде, уже объявлены. В зависимости от браузера, они могут быть равны undefined (в Chrome и Safari), либо, в случае с let и const в браузере Firefox, не равны ничему и иметь специальное состояние uninitialized :
console.log('Старт') var byVar = 5let byLet = 10const byConst = 15 console.log('Конец')
console.log('Старт') var byVar = 5 let byLet = 10 const byConst = 15 console.log('Конец')
В конце скрипта, после того как произошло присвоение стартовых значений, переменные равны 5 , 10 и 15 :
Получается, что некоторое время переменная может содержать значение undefined и быть доступной для чтения. Этим нужно пользоваться с осторожностью.
Переменные let и const
Скопировать ссылку «Переменные let и const» Скопировано
Переменные let и const появились в версии EcmaScript 2015 года (ES6), и сейчас используются намного чаще чем var .
Объявление
Скопировать ссылку «Объявление» Скопировано
Используя ключевое слово let , можно объявить переменную без присвоения ей начального значения. В таком случае она будет равна undefined :
let aconsole.log(a)// undefined a = 5console.log(a)// 5
let a console.log(a) // undefined a = 5 console.log(a) // 5
При помощи const нельзя объявлять переменные без значения:
const a// SyntaxError: Missing initializer in const declaration // Правильноconst b = 5
const a // SyntaxError: Missing initializer in const declaration // Правильно const b = 5
К переменным let и const нельзя обращаться до их объявления в коде:
console.log(a)// ReferenceError: Cannot access 'a' before initializationconsole.log(b)// ReferenceError: Cannot access 'b' before initialization let a = 5const a = 5
console.log(a) // ReferenceError: Cannot access 'a' before initialization console.log(b) // ReferenceError: Cannot access 'b' before initialization let a = 5 const a = 5
Почему так?
У let и const есть так называемая temporal dead zone (TDZ) — момент выполнения скрипта до объявления переменной. Переменная может использоваться и выше объявления, при условии, что содержащая её часть кода будет выполнена после инициализации:
function foo() console.log('from foo', a)> Promise.resolve() .then(() => console.log('from promise', a)) setTimeout(() => console.log('from timer',a)) let a = 10 foo() // 'from foo 10', 'from promise 10', 'from timer 10'
function foo() console.log('from foo', a) > Promise.resolve() .then(() => console.log('from promise', a)) setTimeout(() => console.log('from timer',a)) let a = 10 foo() // 'from foo 10', 'from promise 10', 'from timer 10'
TDZ есть также и у ES6-классов, несмотря на то, что они являются «синтаксическим сахаром» над обычными функциями.
console.log(Foo) class Foo constructor(bar) this.bar = bar >>// ReferenceError: Cannot access 'Foo' before initialization
console.log(Foo) class Foo constructor(bar) this.bar = bar > > // ReferenceError: Cannot access 'Foo' before initialization
А функции (объявленные как Function Declaration) TDZ не имеют.
console.log(Foo) function Foo() this.bar = bar>// ƒ Foo()
console.log(Foo) function Foo() this.bar = bar > // ƒ Foo()
Оба типа переменных имеют блочную область видимости и не становятся частью глобального объекта ( window в браузере, global в Node.js). Блочная область видимости не даёт получить значение переменной вне блока, где она была объявлена.
Если объявить переменные внутри блока if , то обращение к ним вне блока будет выбрасывать ошибку:
if (true) let a = 5 const b = 10 console.log(a) // 5 console.log(b) // 10> console.log(a)// ReferenceError: a is not defined console.log(b)// ReferenceError: b is not defined
if (true) let a = 5 const b = 10 console.log(a) // 5 console.log(b) // 10 > console.log(a) // ReferenceError: a is not defined console.log(b) // ReferenceError: b is not defined
Одинаковые имена переменных
Скопировать ссылку «Одинаковые имена переменных» Скопировано
Объявление переменной с именем, которое уже используется в текущей области видимости, приведёт к ошибке:
let a = 5 let a = 10// SyntaxError: Identifier 'a' has already been declared
let a = 5 let a = 10 // SyntaxError: Identifier 'a' has already been declared
То же правило работает и при использовании const , и при использовании смешанного подхода:
const a = 5const a = 10// SyntaxError: Identifier 'a' has already been declared var b = 5const b = 10// SyntaxError: Identifier 'b' has already been declared
const a = 5 const a = 10 // SyntaxError: Identifier 'a' has already been declared var b = 5 const b = 10 // SyntaxError: Identifier 'b' has already been declared
В то же время можно объявлять переменные с одинаковым именем в разных областях видимости. В этом случае значение будет зависеть от той области видимости, где происходит чтение:
let name = 'Ольга' if (true) let name = 'Елена' console.log(name) // Елена> console.log(name)// Ольга
let name = 'Ольга' if (true) let name = 'Елена' console.log(name) // Елена > console.log(name) // Ольга
Смена значения в let и const
Скопировать ссылку «Смена значения в let и const» Скопировано
Значение в переменной, созданной через let , можно изменять:
let a = 5console.log(a)// 5 a = 10console.log(a)// 10
let a = 5 console.log(a) // 5 a = 10 console.log(a) // 10
Стартовое значение const изменить нельзя, будь то примитивное значение:
const a = 5a = 10// TypeError: Assignment to constant variable
const a = 5 a = 10 // TypeError: Assignment to constant variable
Или ссылка на объект:
const obj = a: 5,> obj = a: 10,>// TypeError: Assignment to constant variable
const obj = a: 5, > obj = a: 10, > // TypeError: Assignment to constant variable
Однако объект, хранящийся в const , можно мутировать. Объекты хранятся по ссылке, и изменение объекта не приводит к изменению ссылки на него:
const obj = a: 5,> obj.a = 10 console.log(obj)//
const obj = a: 5, > obj.a = 10 console.log(obj) //
Переменные var
Скопировать ссылку «Переменные var» Скопировано
Объявление переменных при помощи ключевого слова var было в JavaScript с первых версий.
Объявление
Скопировать ссылку «Объявление» Скопировано
Переменные var можно объявлять без присвоения им значения, в таком случае они будут равны undefined :
var aconsole.log(a)// undefined var b = 5console.log(b)// 5
var a console.log(a) // undefined var b = 5 console.log(b) // 5
Переменные, объявленные через var , имеют функциональную область видимости. Они доступны только в пределах текущей функции или глобального объекта, если функции нет:
if (true) var a = 5> function foo() var b = 10> console.log(a)// 5console.log(b)// ReferenceError: b is not defined
if (true) var a = 5 > function foo() var b = 10 > console.log(a) // 5 console.log(b) // ReferenceError: b is not defined
Объявление переменных вне функций делает их глобальными переменными. Они доступны как свойства глобального объекта:
var varVariable = 5 console.log(window.varVariable)// 5
var varVariable = 5 console.log(window.varVariable) // 5
К переменным, объявленным при помощи ключевого слова var , можно обращаться до момента объявления. В отличие от let и const , ошибки это не вызовет. Такое поведение называется hoisting — «всплытие»:
console.log(a)// undefined var a = 5 console.log(a)// 5
console.log(a) // undefined var a = 5 console.log(a) // 5
Разберём, как работает функциональная область видимости:
var a = 5 function foo() console.log(a) // undefined var a = 10 console.log(a) // 10> foo() console.log(a)// 5
var a = 5 function foo() console.log(a) // undefined var a = 10 console.log(a) // 10 > foo() console.log(a) // 5
Перед выполнением функции в глобальной области видимости присутствует переменная a , равная 5 :
Во время выполнения функции формируется новая функциональная область видимости, в которой тоже присутствует переменная a . Эта переменная была объявлена с помощью var внутри функции, в момент выполнения которой она «всплыла» со значением равным undefined . В строке 4 происходит обращение именно к ней (до её объявления), а не к той, что находится вне функции.
В строке 8 значение переменной a уже равно 10.
После выполнения функции локальная область видимости была удалена. В консоли выводится глобальная переменная a .
Более подробно об этом можно прочитать в отдельной статье
Смена значения в var
Скопировать ссылку «Смена значения в var» Скопировано
Значение, хранящееся в переменной var , можно изменить двумя способами:
- обратиться к имени переменной и присвоить новое значение:
var a = 5console.log(a)// 5 a = 10console.log(a)// 10
var a = 5 console.log(a) // 5 a = 10 console.log(a) // 10
- обратиться к имени переменной вместе с ключевым словом var :
var a = 5console.log(a)// 5 var a = 10console.log(a)// 10
var a = 5 console.log(a) // 5 var a = 10 console.log(a) // 10
На практике
Скопировать ссылку «На практике» Скопировано
Сергей Фомин советует
Скопировать ссылку «Сергей Фомин советует» Скопировано
В новом коде используйте только let или const . Используйте let в тех случаях, когда значение переменной меняется. Во всех остальных используйте const . Проще всего всегда по умолчанию использовать ключевое слово const и исправлять объявление переменной на let , если появляется нужда изменить её значение далее в коде.
Называйте переменные так, чтобы можно было легко понять, что в них хранится. Например:
let url = 'https://doka.guide' const now = Date.now() const user = name: 'John', age: 30,>
let url = 'https://doka.guide' const now = Date.now() const user = name: 'John', age: 30, >
Исключением считается именование счётчиков в циклах for , в которых обычно используются одиночные буквы i , j , и так далее.
Имена переменных могут состоять из нескольких слов, поэтому для удобства их чтения в JavaScript принято использовать так называемую «верблюжью нотацию» (camelCase), когда каждое новое слово, начиная со второго, пишется с заглавной буквы:
const fullName = 'John Doe' const arrayOfNumbers = [1, 2, 3]
const fullName = 'John Doe' const arrayOfNumbers = [1, 2, 3]
Имена констант (переменные, которые не меняют своё значение) принято писать, используя screaming_snake_case. В данной нотации все слова пишутся заглавными буквами, а разделителем является символ _ .
const BASE_URL = 'https://doka.guide' const PORT = 3000 const UNAUTHORIZED_CODE = 401
const BASE_URL = 'https://doka.guide' const PORT = 3000 const UNAUTHORIZED_CODE = 401
+ Развернуть
На собеседовании
Скопировать ссылку «На собеседовании» Скопировано
В чём разница между null , undefined и объявленной переменной без начального значения? ( let foo; )
Скопировать ссылку «В чём разница между null, undefined и объявленной переменной без начального значения? (let foo;)» Скопировано
Скопировать ссылку «Александр Рассудихин отвечает» Скопировано
null обычно задаётся переменной явно и означает, что она ничего не содержит. undefined показывает, что значение переменной «не определено». undefined обычно присваивается переменной, когда она была объявлена, но не было определено её начальное значение. Также, undefined может возвращаться и из функции — это происходит, если функции явно не возвращает ничего другого. null же обычно возвращают из функции явно, чтобы показать, что результат функции равен «ничему».
Без начального значения можно оставлять только переменную объявленную через let или var . Если объявить переменную через const и не задать ей начального значения, будет ошибка: Uncaught SyntaxError : Missing initializer in const declaration .
Оператор typeof для null работает странно. typeof ( null ) выдаст нам строку ‘object’. Это официально признанная ошибка в языке, сохраняемая для совместимости. Ошибка тут в том, что null это отдельный тип данных, а не объект. С undefined всё куда лучше и typeof ( undefined ) выдаст нам ‘undefined’. Почитать ещё о typeof можно здесь.
Поговорим немного о приведении типов. Для начала, пример:
console.log(null + null); // 0console.log(undefined + undefined); // NaN
console.log(null + null); // 0 console.log(undefined + undefined); // NaN
null во время сложения приводится к нулю. Это логично, так как числовым значением «ничего» является как раз 0.
С undefined другое поведении, так как JavaScript пытается привести его к числу, но у него не получается и в результате мы получаем NaN .Немного упомяну и про оператор нулевого слияния ( ? ? ). В выражении между двумя операндами, он будет возвращать первый операнд, если он не равен null или undefined . Можно сказать, что ? ? приравнивает смысл undefined и null к «ничего не содержит» и в этом случае, кладёт в переменную значение второго операнда.
Разница между let , const и var ?
Скопировать ссылку «Разница между let, const и var?» Скопировано
Скопировать ссылку «Алексей Филимонов отвечает» Скопировано
Переменные объявленные через var всплывают (hoisting).
Это значит, что если мы обратимся к переменной ещё до момента её инициализации, то получим undefined .console.log(a); // Не может получить доступ к 'a' до её инициализацииconsole.log(b); // Не может получить доступ к 'b' до её инициализацииconsole.log(c); // undefined let a = 10;const b = 20;var c = 30;
console.log(a); // Не может получить доступ к 'a' до её инициализации console.log(b); // Не может получить доступ к 'b' до её инициализации console.log(c); // undefined let a = 10; const b = 20; var c = 30;
У переменных let , const и var разная область видимости.
У let и const область видимости ограничена блоком, а не функцией.
Другими словами, если переменные let и const объявлены внутри < . . . >, то доступны только там и на всех вложенных уровнях. Переменная, объявленная через var такую область видимости игнорирует и может быть доступна за её пределами.if (true) let a = 10; const b = 20; var c = 30;> console.log(a); // ReferenceErrorconsole.log(b); // ReferenceErrorconsole.log(c); // 30
if (true) let a = 10; const b = 20; var c = 30; > console.log(a); // ReferenceError console.log(b); // ReferenceError console.log(c); // 30
Переменная, объявленная через const становиться константой и её невозможно переопределить. При попытке это сделать мы получим ошибку.
let a = 10;const b = 20; a = 15 // Все впорядкеb = 40 // TypeError
let a = 10; const b = 20; a = 15 // Все впорядке b = 40 // TypeError
Ключевое слово let
В редакцию ES2015 были введены два новых важных ключевых слова JavaScript — let и const.
Эти два ключевых слова позволяют в JavaScript декларировать переменные и константы с областью видимости внутри блока.
До редакции ES2015 в JavaScript было только два типа области видимости — глобальная и внутри функции.
Глобальная область видимости
Переменные, декларированные глобально (вне какой-либо функции), обладают глобальной областью видимости.
var carName = "Volvo"; // расположенный здесь код может использовать переменную carName function myFunction() < // расположенный здесь код также может использовать переменную carName >
Доступ к глобальным переменным можно получить из любого места программы на JavaScript.
Область видимости внутри функции
Переменные, декларированные локально (внутри какой-либо функции), обладают областью видимости внутри функции.
// расположенный здесь код не может использовать переменную carName function myFunction() < var carName = "Volvo"; // расположенный здесь код может использовать переменную carName >
Доступ к локальным переменным можно получить только внутри той функции, где эти переменные были декларированы.
Область видимости внутри блока
Переменные, декларированные при помощи ключевого слова var, не обладают областью видимости внутри блока.
Т.е. доступ к таким переменным, декларированным внутри блока , можно получить и вне этого блока.
< var x = 2; >// здесь переменную x МОЖНО использовать
До редакции ES2015 в JavaScript не было области видимости внутри блока.
Начиная с редакции ES2015 переменные, декларированные при помощи ключевого слова let, приобретают область видимости внутри блока. В результате этого переменные, декларированные таким образом внутри блока , становятся недоступными за пределами этого блока.
< let x = 2; >// здесь переменную x НЕЛЬЗЯ использовать
Передекларирование переменных
Передекларирование переменной при помощи ключевого слова var может вызвать проблемы.
Так, если передекларировать переменную внутри блока, то она будет перекларирована и за его пределами:
var x = 10; // Здесь значение x равно 10 < var x = 2; // Здесь значение x равно 2 >// Здесь значение x равно 2
Решить эту проблему можно, если передекларировать переменную при помощи ключевого слова let.
В этом случае передекларирование переменной внутри блока не будет передекларировать переменную за пределами этого блока:
var x = 10; // Здесь значение x равно 10 < let x = 2; // Здесь значение x равно 2 >// Здесь значение x равно 10
Область видимости внутри цикла
Использование ключевого слова var в цикле:
var i = 5; for (var i = 0; i < 10; i++) < // какой-то код >// Здесь значение i равно 10
Использование ключевого слова let в цикле:
let i = 5; for (let i = 0; i < 10; i++) < // какой-то код >// Здесь значение i равно 5
В первом примере переменная, декларированная в цикле при помощи ключевого слова var, также передекрарирует переменную за пределами цикла.
Во втором примере переменная, декларированная в цикле с ключевым словом let, не передекрарирует переменную за пределами цикла, оставляя неизменным ее значение, так как использование ключевого слова let для декларирования переменной i в цикле делает переменную i видимой только внутри этого цикла.
Область видимости внутри функции
Поведение переменных, декларированных внутри функции при помощи ключевых слов var и let, одинаковое. В обоих случаях у переменных будет локальная область видимости.
function myFunction() < var carName = "Volvo"; // Область видимости внутри функции >function myFunction() < let carName = "Volvo"; // Область видимости внутри функции >
Глобальная область видимости
Поведение переменных, декларированных вне блока при помощи ключевых слов var и let, одинаковое. В обоих случаях у переменных будет глобальная область видимости.
var x = 2; // Глобальная область видимости let x = 2; // Глобальная область видимости
Глобальные переменные в HTML
В JavaScript глобальная область видимости распространяется на все окружение JavaScript.
В HTML глобальная область видимости — это глобальный объект window.
Глобальные переменные, декларированные при помощи ключевого слова var, принадлежат глобальному объекту window:
var carName = "Volvo"; // здесь код может использовать window.carName
Глобальные переменные, декларированные при помощи ключевого слова let, не принадлежат глобальному объекту window:
let carName = "Volvo"; // здесь код не может использовать window.carName
Передекларирование
Передекларировать переменную JavaScript при помощи ключевого слова var можно в любом месте программы:
var x = 2; // Значение x равно 2 var x = 3; // Теперь значение x равно 3
Нельзя передекларировать переменную, которая была декларирована при помощи ключевого слова var, при помощи ключевого слова let в той же области видимости или в том же блоке:
var x = 2; // Можно let x = 3; // Нельзя < var x = 4; // Можно let x = 5 // Нельзя >
Нельзя передекларировать переменную, которая была декларирована при помощи ключевого слова let, при помощи ключевого слова let в той же области видимости или в том же блоке:
let x = 2; // Можно let x = 3; // Нельзя < let x = 4; // Можно let x = 5; // Нельзя >
Нельзя передекларировать переменную, которая была декларирована с ключевым словом let, при помощи ключевого слова var в той же области видимости или в том же блоке:
let x = 2; // Можно var x = 3; // Нельзя < let x = 4; // Можно var x = 5; // Нельзя >
Передекларировать переменную при помощи ключевого слова let в другой области видимости или в другом блоке можно:
let x = 2; // Можно < let x = 3; // Можно > < let x = 4; // Можно >
Поднятие
Переменные, декларированные при помощи ключевого слова var, «поднимаются» в верх JavaScript кода (если вы не знаете, что такое «поднятие» в JavaScript, то см. главу Поднятие переменных в Javascript).
Таким образом, мы можем использовать такие переменные до того, как они будут декларированы:
// здесь МОЖНО использовать carName var carName;
Переменные, декларированные при помощи ключевого слова let, не «поднимаются» в верх JavaScript кода.
Использование переменной, декларированной при помощи ключевого слова let, до ее реальной декларации приведет к ошибке ReferenceError.
В этом случае такая переменная находится в, так называемой, «временной мертвой зоне» с начала блока и до ее декларации:
// здесь НЕЛЬЗЯ использовать carName let carName;
Var, Let и Const: в чем разница?
Перевод статьи «Var, Let, and Const – What’s the Difference?».
С выходом ES2015 (ES6) мы получили много нового отличного функционала. С учетом того, что сейчас уже 2020 год, можно предположить, что большинство JavaScript-разработчиков со всеми новшествами уже ознакомились и начали их применять на практике.
Но может быть и так, что для некоторых программистов произошедшие изменения так и остались тайной за семью печатями.
Одним из важных новшеств ES6 было появление операторов let и const , используемых для объявления переменных. Но чем эти операторы отличаются от старого доброго var , который мы использовали раньше? Если вы все еще не разобрались в этом, наша статья вам поможет.
В этой статье мы обсудим разницу между var , let и const в разрезе их области видимости и поднятия.
Var
До наступления эпохи ES6 в объявлении переменных царил оператор var . Но объявление переменных при помощи этого оператора приводило к некоторым проблемам. Именно поэтому возникла необходимость ввода в язык новых способов объявления переменных. Но прежде чем перейти к разбору проблем, давайте остановимся на применении оператора var .
Область видимости переменных, объявленных при помощи var
Область видимости это часть программы, в которой будет доступна объявленная переменная. Переменные, объявленные при помощи var , могут иметь как глобальную, так и локальную область видимости.
Мы говорим о глобальной области видимости, когда переменная объявлена вне функции. Это означает, что любая переменная, объявленная при помощи оператора var вне блока функции, будет доступна во всем window .
Но если переменная объявляется при помощи var внутри функции, она имеет локальную область видимости. Это означает, что доступ к ней есть только в рамках этой функции.
Чтобы разобраться, давайте рассмотрим пример.
var greeter = «hey hi»; function newFunction()
В этом примере greeter имеет глобальную область видимости, потому что существует вне функции. А вот область видимости hello локальна. У нас нет доступа к переменной hello вне функции, в которой она объявлена. Поэтому, если мы сделаем так, то получим ошибку:
var tester = "hey hi"; function newFunction() < var hello = "hello"; >console.log(hello); // error: hello is not defined
Мы получили ошибку, поскольку переменная hello недоступна вне функции.
Переменные, объявленные при помощи var, могут как объявляться заново, так и обновляться
То есть, мы можем сделать вот так:
var greeter = "hey hi"; var greeter = "say Hello instead";
— и это не приведет к ошибке.
И вот так мы тоже не получим ошибок:
var greeter = "hey hi"; greeter = "say Hello instead";
Поднятие (hoisting) var
В JavaScript поднятие это механизм, обеспечивающий перемещение объявлений переменных и функций в верх их области видимости перед выполнением кода. Это означает, что если мы сделаем так:
console.log (greeter); var greeter = "say hello"
интерпретироваться это будет как:
var greeter; console.log(greeter); //greeter is undefined greeter = "say hello"
Таким образом, переменные, объявленные при помощи var , поднимаются в верх своей области видимости и инициализируются присвоением какого-нибудь значения или undefined .
Проблемы, возникающие при использовании var
Чтобы пояснить, в чем недостаток использования var , обратимся к примеру.
var greeter = "hey hi"; var times = 4; if (times > 3) < var greeter = "say Hello instead"; >console.log(greeter) //"say Hello instead"
Поскольку times > 3 возвращает истину, переменная greeter объявляется повторно со значением «say Hello instead» . Это не проблема, если вы знаете, что делаете, и действительно хотите заново объявить переменную greeter . Но если вы не осознаете, что эта переменная уже объявлялась, вы столкнетесь с проблемами.
Если вы использовали greeter в других частях вашего кода, вы можете быть удивлены результатами работы программы. Скорее всего, у вас появится много багов. Вот поэтому нам нужны let и const .
Let
Сейчас при объявлении переменных предпочтение отдается let . Это совершенно не удивительно, потому что оператор let и задумывался как улучшенный вариант var . Помимо прочего, он решает проблему, которую мы осветили в предыдущем разделе. Давайте посмотрим, каким образом он это делает.
let имеет блочную область видимости
Блок это отрывок кода внутри фигурных скобок. Любой код, окруженный фигурными скобками, — блок.
Переменная, объявленная в блоке кода при помощи оператора let , доступна для использования только в рамках этого блока кода.
(Отличие от просто локальной переменной в том, что здесь область видимости не функция, а блок кода. Причем этот блок может иметь и вложенные блоки. — Прим. ред.)
Давайте рассмотрим пример.
let greeting = "say Hi"; let times = 4; if (times > 3) < let hello = "say Hello instead"; console.log(hello);//"say Hello instead" >console.log(hello) // hello is not defined
Мы видим, что использование переменной hello вне ее блока (т. е., за пределами кода, ограниченного фигурными скобками, в котором была объявлена переменная) приводит к ошибке. Это потому, что переменные, объявленные при помощи let , имеют блочную область видимости.
Переменные, объявленные при помощи let, могут обновляться, но не объявляться повторно
Как и переменные, объявленные при помощи оператора var , переменные, объявленные с использованием let , могут обновляться в пределах их видимости. Но в отличие от var , let не позволяет повторно объявлять переменную в рамках ее области видимости.
Так что этот код будет работать нормально:
let greeting = "say Hi"; greeting = "say Hello instead";
а этот вернет ошибку:
let greeting = "say Hi"; let greeting = "say Hello instead";//error: Identifier 'greeting' has already been declared
Тем не менее, если объявлять переменную с одним именем в разных областях видимости, ошибки не будет:
let greeting = "say Hi"; if (true) < let greeting = "say Hello instead"; console.log(greeting);//"say Hello instead" >console.log(greeting);//"say Hi"
Почему здесь нет ошибки? Потому что эти два экземпляра переменных находятся в разных областях видимости и вследствие этого воспринимаются как совершенно разные переменные.
В связи с этой особенностью оператор let будет лучшим выбором, чем var . Используя let , вам не нужно беспокоиться о том, использовали ли вы это имя переменной раньше, потому что каждая такая переменная существует только в рамках своего блока.
Кроме того, поскольку переменную в рамках ее области видимости нельзя объявить повторно, исчезает проблема, которая возникала при использовании var.
Поднятие let
Объявления переменных при помощи let тоже поднимаются вверх. Но в отличие от переменных, объявленных при помощи var, которые могут инициализироваться как undefined , ключевое слово let такого не позволяет. Так что если вы попытаетесь использовать переменную, объявленную при помощи let , до ее декларирования, вы получите Reference Error .
Const
Переменные, объявленные с использованием const , содержат постоянные значения. Объявление переменных при помощи const имеет некоторое сходство с объявлением при помощи let .
Переменные, объявленные при помощи const, имеют блочную область видимости
Как и переменные, объявленные при помощи оператора let , переменные, объявленные с использованием const , доступны только в рамках того блока, внутри которого их объявили.
Переменные, объявленные при помощи const, нельзя обновить или объявить заново
То есть, значение переменной, объявленной при помощи const , остается неизменным внутри ее области видимости. Эту переменную нельзя объявить заново или обновить. Поэтому, объявляя переменную при помощи const , мы не можем сделать ни так:
const greeting = "say Hi"; greeting = "say Hello instead";//error : Assignment to constant variable.
const greeting = "say Hi"; const greeting = "say Hello instead";//error : Identifier 'greeting' has already been declared
Вследствие этого каждая переменная, объявленная с использованием const , должна быть инициализирована при объявлении.
Это поведение несколько отличается, когда речь идет об объектах, объявленных при помощи const . Хотя такой объект не может быть обновлен, свойства этого объекта обновлять можно. То есть, если мы объявим объект следующим образом:
const greeting =
мы не сможем сделать так:
const greeting = < words : "Hello", number : "five" >//error : Assignment to constant variable.
а вот так — сможем:
greeting.message = "say Hello instead";
Значение greeting.message обновится без всяких ошибок.
Поднятие const
Переменные, объявленные при помощи оператора const , тоже поднимаются вверх, но при этом не инициализируются.
Итоги
На случай, если вы все же не уловили разницу между var , let и const , повторим:
- Переменные, объявленные при помощи var , имеют глобальную или локальную (в рамках функции) область видимости. Если вы объявляете переменные с использованием let или const , их область видимости будет блочной.
- Переменные, объявленные при помощи var , могут обновляться и объявляться заново. Использование let позволяет обновлять переменную, но не объявлять заново, а использование const не предполагает ни того, ни другого.
- Переменные всех видов поднимаются в верх своей области видимости. Но переменные, объявленные при помощи var , инициализируются как undefined , а объявленные с использованием let или const — не инициализируются.
- При помощи var или let можно объявлять переменные без их инициализации, но если вы объявляете переменную при помощи const , она должна инициализироваться при объявлении.