Что такое поднятие переменных js
Поднятие в JS (Hoisting в Javascript + 3 примера)
В этой статье мы с вами разберемся как что такое, и как работает поднятие (Hoisting) в Javascript. Эта одна из базовых тем в ванильном JS и вы однозначно наткнетесь на нее в одном из интервью при устройстве на работу.
Поднятие в JS (пример с функцией)
Для нашего примера создадим функцию letsGo и попробуем ее вызвать до ее создания.
Наша функция запускается, и мы получаем строку «Go!!» в нашей консоли. Это происходит, так как срабатывает мехнаизм «поднятие» в Javascript.
То есть, «под капотом» компилятор JS «поднимает» все строчки, где объявляются функции на самый верх.
Ваглядит это так:
Теперь, давайте немного расширим наш пример и создадим еще одну функцию add.
Мы видим, что наша вторая функция add также срабатывает и получаем результат сложения в консоли. То есть, опять, сработал механизм «поднятия» в JS, который поднял весь код, где объявляются функции на самый верх.
Применительно к функциям, «поднятие» работает только с объявлением функций!
Поднятие в JS не работает при использовании функциональных выражений, стрелочных функций и любых других способов создания функций.
То есть, если мы попробуем использовать функциональное выражение и запустить функцию до ее создания, то получим ошибку:
Если решим написать то же самое, используя стрелочную функцию, тоже получим ошибку («поднятие» не работает):
Поднятие в Javascript (пример с переменной var)
Давайте, ради интереса, также выведем в лог произвольную переменную, которой у нас вообще не существует:
То есть, когда мы выводим в лог значение переменной years, до ее создания, происходит следующее:
Обработчики Событий в JS (как работает addEventListener)
Замыкания в Javascript (что такое замыкание в JS + 3 примера)
Область видимости в JavaScript и «поднятие» переменных и объявлений функций
Вы знаете, какое значение выведет этот код на JavaScript?
Если вас удивляет, что выведется «10», то следующий код вас и вовсе запутает:
В этом случае браузер выведет «1». Так что, собственно, происходит? Хотя такое поведение кажется странным, опасным и сбивающим с толку, на самом деле это очень мощное и выразительное средство JavaScript. Я не знаю, есть ли официальное название для такого поведения, но мне нравится использовать термин «поднятие»(«hoisting»). В этой статье я попытаюсь пролить свет на этот механизм языка, но сначала давайте поговорим об области видимости в JavaScript.
Область видимости в JavaScript
Одна из причин, приводящих в замешательство новичков, — это область видимости. Вообще, не только новичков. Я встречал много опытных JavaScript-разработчиков, которые не понимают механизм области видимости в JavaScript. Причина в том, что внешне JavaScript очень похож на любой другой Си-подобный язык.
Давайте рассмотрим следующий код на Cи:
Эта программа выведет 1, 2, 1, потому что Си и все остальные Си-подобные языки реализуют области видимости на уровне блоков кода. Когда исполняется новый блок кода, например условие if, новые переменные, объявленные в нём, не повлияют на переменные внешней области видимости.
Но не в случае JavaScript. Попробуйте запустить вот этот код в Firebug:
На этот раз будут выведены числа 1, 2, 2. Это связано с тем, что в JavaScript используется область видимости на уровне функций. Это совсем не то, что мы привыкли видеть в языках программирования, вроде Си. Блоки кода, вроде того, который у нас идёт сразу после if, не создают новую область видимости. Только функции создают новые области видимости.
Для многих программистов, привыкших к Си, C++, C# или Java такое поведение очень неожиданное и неприятное. К счастью, благодаря гибкости функций JavaScript, можно обойти эту проблему. Чтобы создать временную область видимости внутри функции, достаточно сделать следующее:
Такой подход достаточно гибок и может быть использован везде, где вам нужна временная область видимости, не только внутри блоков кода. Но я настаиваю на том, чтобы вы всё-таки потратили своё время, чтобы понять реализацию области видимости в JavaScript. Это довольно мощная особенность языка, которая мне очень нравится. Если вы понимаете область видимости, вам проще будет разобраться в «поднятии» переменных и объявлений функций.
Объявления, именование и «поднятие» переменных и функций
на самом деле интерпретируется так:
Оказывается, не важно, будет ли вообще выполнена строка, в которой происходит объявление. Следующие две функции эквивалентны:
Обратите внимание, что присваивание значений переменным не поднимается вместе с их объявлением. Поднимаются только объявления переменных. В случае с функциями, поднимается вся функция целиком. Существуют два основных способа объявить функцию, давайте их рассмотрим:
в этом случае поднимается только функция bar. Идентификатор «foo» также поднимается, но не анонимная функция — она остаётся на месте.
Вот мы и описали основные моменты «поднятия» переменных и функций. Конечно, JavaScript не был бы сам собой, если бы не было особых случаев, в которых всё немного сложнее.
Разрешение имён
Именованные функциональные выражения
Вы можете давать имена функциям, определённым с помощью функциональных выражений, используя синтаксис определения функций. Это не приводит к объявлению функции, а следовательно, имя функции ни добавляется в область видимости, ни поднимается вместе с телом функции в начало области видимости. Вот несколько строк, чтобы проиллюстрировать, что я имею в виду:
Как писать код, обладая такими знаниями
Итак, теперь вы понимаете область видимости и «поднятие» переменных и объявлений функций. Что это означает применительно к написанию кода на JavaScript? Самое главное — всегда объявлять ваши переменные, используя var. Я настаиваю на том, чтобы у вас был ровно один var на область видимости и чтобы он располагался в её начале. Если вы заставите себя так делать, у вас никогда не будет проблем, связанных с «поднятием». Тем не менее, это может привести к тому, что сложно следить за переменными, которые объявлены в текущей области видимости. Я рекомендую использовать JSLint с включённой опцией onevar, чтобы вынудить вас так делать. Если вы будете так всё делать, ваш код будет выглядеть примерно так:
Что говорит стандарт
Если инструкция переменной встречается внутри ОбъявленияФункции, переменные объявляются внутри локальной области видимости для данной функции согласно описанию в разделе 10.1.3. В противном случае они объявляются в глобальной области видимости (т.е. создаются как поля глобального объекта согласно описанию в разделе 10.1.3) с использованием атрибутов свойств < DontDelete >. Переменные создаются, когда происходит вход в область выполнения. Блок не определяет новой области выполнения. Только Программа и ОбъявлениеФункции создают новую область видимости. Переменные инициализируются при создании значением undefined. Переменной, для которой определён Инициализатор, присваивается значение его ВыраженияПрисваивания в момент выполнения ИнструкцииПеременной, а не в момент создания переменной.
Поднятие или hoisting в JavaScript
Что такое «поднятие» и как оно работает в JavaScript.
Поднятие предполагает, что объявления переменных var и функций function физически перемещаются в начало кода, но, на самом деле это не так.
Объявления переменных и функций помещаются в память на этапе компиляции, но они остаются именно там, где мы ввели их в свой код.
Одним из преимуществ JavaScript является помещение объявления функций в память, перед выполнением любого сегмента кода. Объявления функций поднимаются, но они идут на самый верх, поэтому они будут находиться над всеми объявлениями переменных. Это позволяет нам использовать функцию до того, как мы объявим её в своем коде. Например:
Поднятие хорошо сотрудничает с другими типами данных. Переменные можно инициализировать и использовать до их объявления.
JavaScript поднимает только объявления, а не инициализации. Если переменная объявлена и инициализирована после её использования, значение будет неопределенным (undefined). Например:
Если мы объявляем переменную после её использования, но предварительно инициализируем её, она вернет значение:
Функции полностью подняты. Означает, что объявлению функции, на этапе создания, было назначено место в памяти.
Поднятие const, let и var
Ключевое слово var
Приведенный выше код, из-за поднятия эквивалентен приведенному коду ниже.
Ключевые слова const / let
Поднятие в JavaScript
Хочешь проверить свои знания по JS?
Подпишись на наш канал с тестами по JS в Telegram!
Поднятие (англ. hoisting) в JavaScript позволяет использовать функции и переменные до их объявления. В этой статье мы разберем, что собой представляет поднятие и как оно работает.
Что такое поднятие в JavaScript?
Взгляните на этот код и попробуйте угадать, что произойдет при его запуске:
Дело в том, что интерпретатор JavaScript разделяет объявление и назначение значений для функций и переменных. Ваши объявления «поднимаются» вверх их области видимости перед выполнением.
Этот процесс называется поднятием. Именно благодаря ему мы можем использовать переменную foo в нашем примере еще до того, как она объявлена.
Давайте еще немного глубже погрузимся в тему поднятия функций и переменных и постараемся разобраться, как это все работает.
Поднятие переменных в JavaScript
Чисто в качестве напоминания: мы объявляем переменные при помощи операторов var, let и const. Например:
Мы назначаем значение переменной, используя оператор присваивания:
Во многих случаях объявление и присваивание значения комбинируются в один шаг:
Поднятие переменных, объявленных при помощи var
Как мы установили ранее, в основе поднятия лежит тот факт, что интерпретатор разделяет объявление переменных и присвоение им значений. Мы можем сделать то же самое вручную, разделив объявление и присвоение значения на два шага:
Использовав необъявленную переменную до присвоения ей значения, вы также получите ошибку ReferenceError, потому что здесь нет объявления, которое могло бы подняться:
Теперь вы, вероятно, думаете: «Хм. Это как-то странно, что JavaScript позволяет получить доступ к переменным до того как они объявлены». Это поведение — необычная часть JavaScript. Оно может привести к ошибкам, поэтому использование переменной до ее объявления обычно нежелательно.
Поднятие переменных, объявленных при помощи let и const
Обратите внимание, что интерпретатор по-прежнему поднимает foo: сообщение об ошибке говорит нам, что где-то эта переменная инициализирована.
Временная мертвая зона
TDZ начинается в начале области видимости переменной и заканчивается ее объявлением. Обращение к переменной в TDZ приводит к выбросу ReferenceError.
Вот пример понятного блока, показывающего начало и конец временной мертвой зоны foo:
TDZ также присутствует в дефолтных параметрах функции, которые оцениваются слева направо. В следующем примере bar находится в TDZ, пока не получает значение по умолчанию:
Но этот код работает, потому что мы можем обратиться к foo вне ее TDZ:
typeof во временной мертвой зоне
Это поведение согласуется с другими примерами с let и const в TDZ, которые мы уже видели. Здесь мы получаем ReferenceError, потому что foo объявлена, но не инициализирована. Мы должны знать, что используем ее до инициализации.
Кроме того (и это удивительно), мы можем проверить тип несуществующей переменной и не получить ошибку. typeof безопасно возвращает строку:
Фактически, появление let и const сломало гарантию того, что typeof всегда возвращает строковое значение для любого операнда.
Поднятие функций в JavaScript
Объявления функций тоже поднимаются. Это позволяет нам вызывать функцию до ее объявления. Например, следующий код успешно запускается и выдает результат «foo»:
Обратите внимание, что поднимаются только объявления функций, не функциональные выражения. В этом есть смысл: как мы только что разобрали, присвоения значений переменным не поднимаются.
Если мы попытаемся вызвать переменную, которой было присвоено в качестве значения функциональное выражение, мы получим TypeError или ReferenceError — в зависимости от области видимости переменной:
Это отличается от вызова вообще не объявленной функции, который вызвал бы другую ошибку — ReferenceError:
Как использовать поднятие в JavaScript
Поднятие переменных
Если вы работаете над старой кодовой базой или вам еще по какой-то причине приходится использовать var, MDN рекомендует писать var-объявления как можно выше в области видимости. Таким образом скоуп ваших переменных будет яснее.
Вы также можете подумать над использованием правила no-use-before-define в ESLint, чтобы точно не использовать переменные до их объявления.
Поднятие функций
Поднятие функций — вещь полезная. Мы можем спрятать реализацию функции внизу файла и таким образом дать читателю сосредоточиться на том, что вообще делает наш код. То есть, благодаря такому подходу, мы можем открыть файл и сразу увидеть, что делает код, не разбираясь в его реализации.
Вот вам надуманный пример:
Взглянув на этот код, мы сразу получаем представление о том, что он делает, и нам для этого не приходится сначала прочесть все объявления функций.
Тем не менее, использование функций до их объявления — дело вкуса. Некоторые разработчики, например Wes Bos, предпочитают другой путь. Они помещают функции в модули, которые можно импортировать при необходимости. (Источник: Wes Bos).
Руководство по стилю от Airbnb идет еще дальше. Чтобы предотвратить обращение до объявления, гайд советует отдавать предпочтение именованным функциональным выражениям, а не объявлениям:
«Объявления функций поднимаются, а это означает, что слишком велик соблазн обратиться к функции до того, как она определена в файле. Это вредит читаемости и поддерживаемости.
Если вы полагаете, что определение функции настолько большое и сложное, что помешает читателю понять остальной файл, возможно, пора выделить это определение в модуль!»
Заключение
Спасибо за внимание! Надеюсь, эта статья помогла вам познакомиться с темой поднятия в JavaScript.
Поднятие переменных в Javascript
«Поднятие» (hoisting) – это поведение JavaScript по умолчанию, когда любая декларация передвигается вверх области видимости.
Декларации в JavaScript поднимаются
В JavaScript переменная может декларироваться уже после использования.
Другими словами, переменная может использоваться до того, как она будет декларирована.
Ниже, результат в примере 1 будет таким же, что в примере 2.
Пример 1
Пример 2
Чтобы в этом разобраться, необходимо понять сам термин «поднятие».
«Поднятие» (hoisting) – это поведение JavaScript по умолчанию, когда все декларации передвигаются вверх текущей области видимости (вверх текущего скрипта или текущей функции).
Инициализации не поднимаются
В JavaScript поднимаются только декларации, а не инициализации.
Ниже, результат в примере 1 будет не таким же, что в примере 2.
Пример 1
Пример 2
В последнем примере будет выведено undefined как значение переменной y. Это вызвано тем, что только декларации (var y), а не инициализации (=7) поднимаются вверх.
Благодаря «подъему» переменная y была декларирована перед использованием, но так как инициализация не поднимается, значение переменной y оказывается неопределенным (undefined).
Пример 2 аналогичен следующей записи:
Всегда декларируйте переменные в начале!
Для многих разработчиков «подъем» остается неизвестным или упускаемым из виду поведением JavaScript.
Если разработчик не учитывает «подъем», то в коде могут появляться ошибки.
Чтобы избежать подобных ошибок, всегда декларируйте все переменные в начале содержащей их области видимости. Учитывая то как JavaScript интерпретирует код, это будет хорошим правилом.
Внимание! В строгом режиме JavaScript не допускает использование переменных, если они не декларированы.