W3docs

Ключевое слово var в JavaScript

Как работает var в JavaScript: область видимости, поднятие, глобальные переменные, повторное объявление, баг замыканий в цикле, и почему let и const пришли на смену.

В JavaScript то, как вы создаёте и используете переменные, напрямую влияет на поведение кода. Ключевое слово var десятилетиями применялось для объявления переменных. После того как в ES6 появились let и const, var редко является правильным выбором в новом коде — однако вы будете продолжать встречать его в учебниках, на собеседованиях и в устаревших проектах. В этой главе подробно объясняется, как работает var, почему его правила области видимости и поднятия удивляют разработчиков, и когда (если вообще) стоит его использовать сегодня.

На этой странице рассматривается: область видимости var, поднятие и ловушка undefined, случайные глобальные переменные, повторное объявление, знаменитый баг замыканий в цикле, а также более безопасные альтернативы — let/const.

Введение в объявление переменных с помощью var

Ключевое слово var объявляет переменную, опционально инициализируя её значением. Переменные, объявленные через var, имеют функциональную область видимости или глобальную область видимости (но никогда не блочную) и подвергаются поднятию (hoisting), что может приводить к поведению, которое удивляет разработчиков, пришедших из других языков. Основы объявления переменных описаны в разделе Переменные JavaScript.

Функциональная область видимости

Переменная, объявленная с помощью var внутри функции, является локальной для этой функции и доступна в любом месте внутри неё. Принципиально важно: var не соблюдает границы блоков. Даже если переменная объявлена внутри блока — например, в операторе if или цикле for — она «вытекает» наружу и остаётся видимой во всей охватывающей функции.

javascript— editable

Это главное отличие от let и const: с ними x существовал бы только внутри блока if, а console.log выбросил бы ReferenceError. Полную картину блочной области видимости см. в разделе Область видимости переменных.

Поднятие (Hoisting)

Поднятие — это поведение JavaScript, при котором объявления обрабатываются так, будто они перемещены в начало своей области видимости. Для var поднимается только объявление, но не присваивание — поэтому имя переменной существует с начала функции, но хранит undefined до тех пор, пока выполнение не достигнет строки с присваиванием.

javascript— editable

Чтение y до строки с var даёт undefined, а не ReferenceError. Именно в этом тонкость поднятия var: код выглядит так, будто «работает», но опечатка или неверно размещённое присваивание могут незаметно прочитать undefined.

let и const тоже поднимаются, но они находятся в временной мёртвой зоне (temporal dead zone) до момента выполнения их объявления, поэтому обращение к ним раньше выбрасывает исключение вместо того, чтобы молча вернуть undefined — обычно именно это и нужно:

javascript— editable

Глобальные переменные и ключевое слово var

Когда var используется вне какой-либо функции, переменная становится глобальной и доступна откуда угодно. В браузерах она также прикрепляется как свойство глобального объекта (window), чего let и const не делают. Риск в том, что два скрипта, каждый из которых объявляет var config, незаметно перезапишут друг друга.

var globalVar = "I am global";
// In a browser: window.globalVar === "I am global"  → true

let blockGlobal = "scoped";
// window.blockGlobal → undefined (let/const do not become window properties)

Забывание объявить переменную вовсе (присваивание необъявленному имени в режиме без строгого режима) также создаёт случайную глобальную переменную — ещё одна причина использовать "use strict" и предпочитать let/const.

Ограничения var и современные альтернативы

Несмотря на то что var является фундаментальной частью JavaScript, он несёт в себе ограничения, которые привели к появлению let и const в ES6 (ECMAScript 2015), предоставляющих переменные с блочной областью видимости.

Путаница с поднятием и областью видимости

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

Повторное объявление var и особенности замыканий в цикле

  • Повторное объявление: В отличие от let и const, var позволяет повторно объявить одну и ту же переменную в той же области видимости без ошибки — поэтому дублирующее объявление может незаметно перезаписать предыдущее.
  • Замыкание в цикле: Переменная цикла, объявленная через var, находится в одной общей функциональной области видимости, поэтому каждое замыкание, созданное в цикле, видит одну и ту же переменную. К моменту выполнения колбэков цикл завершается, и переменная хранит своё конечное значение.
javascript— editable

Баг замыкания в цикле — классическая ловушка var. Все три колбэка делят одну переменную i:

javascript— editable

Замена var на let решает проблему: let создаёт новую привязку для каждой итерации, поэтому каждое замыкание захватывает собственное значение:

javascript— editable

До появления let обходным решением было использование IIFE, захватывающего значение на каждой итерации:

javascript— editable

Введение let и const

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

Рекомендации по использованию var в JavaScript

Несмотря на свои ограничения, var остаётся частью языка JavaScript и может встречаться, особенно в устаревшем коде. Соблюдение рекомендаций гарантирует, что его использование не навредит функциональности или поддерживаемости кода.

  1. Ограничьте использование в современном коде: Предпочитайте let и const для объявления переменных, чтобы воспользоваться преимуществами блочной области видимости и снизить потенциальные проблемы с поднятием.
  2. Понимайте область видимости: При работе с var учитывайте его функциональную область видимости и планируйте структуру кода соответствующим образом, чтобы избежать непреднамеренных глобальных переменных.
  3. Инициализация при объявлении: Инициализируйте переменные var в момент объявления, чтобы избежать значений undefined из-за поднятия.

Заключение

Ключевое слово var долгое время было краеугольным камнем JavaScript. Понимание его области видимости и поведения при поднятии необходимо для написания надёжного кода. По мере развития языка были введены let и const, устраняющие ограничения var и делающие современный JavaScript более предсказуемым. Тем не менее понимание var остаётся важным для поддержки устаревших кодовых баз. Следуя передовым практикам и отдавая предпочтение объявлениям с блочной областью видимости, разработчики могут писать более чистый и поддерживаемый JavaScript.

Практика

Практика
Какие из следующих утверждений о ключевом слове 'var' в JavaScript верны?
Какие из следующих утверждений о ключевом слове 'var' в JavaScript верны?
Was this page helpful?