Подъем традиционно описывается как подъем чего-либо с помощью веревки или шкива. Я уверен, что вам интересно, как все это относится к кодированию, но подождите, я демистифицирую это для вас. Позвольте мне начать с определения того, что такое подъем с точки зрения сценария Java. Подъем — это вызов функции или переменной перед их инициализацией. С трудом представляю это, вот фрагмент кода, показывающий это. Я думаю, вы можете сказать, что вместо вызова функции и переменной после их инициализации вы поднимаете часть, где вы должны вызывать функцию или переменную, выше точки инициализации, следовательно, поднимаете.

Java Script — это синхронный однопоточный язык программирования, синхронный означает, что он выполняет код последовательно, а однопоточный означает, что он может выполнять только одну строку за раз. Теперь вы задаетесь вопросом, как же тогда вышеупомянутая функция и переменная могут быть вызваны до того, как они будут инициализированы. Чтобы понять это, мы должны немного глубже погрузиться в основы механизма сценариев Java.

После того, как вы запустите свой код сценария Java, есть две фазы, на которых код обрабатывается, первая фаза — это фаза создания памяти, а вторая фаза — фаза выполнения кода. Чтобы также по-настоящему понять эти две фазы, нам нужно узнать о том, что называется глобальным контекстом выполнения. Глобальный контекст выполнения похож на сцену, на которой выступают актеры (ваш код). Это место, где начинает выполняться ваш код, пространство верхнего уровня, где существуют ваши переменные, функции и операторы. Он создается, когда код начинает выполняться, и завершается после выполнения кода.

Можно сказать, что глобальный контекст выполнения разделен на эти две фазы. На первом этапе вы можете сказать, что движок Java Script как бы просматривает код, и всем переменным и функциям назначается пространство памяти, но есть вариация в том, как переменные и функции назначаются этим пространствам памяти. В переменных им просто присваивается значение undefined, в то время как в функциях, специально объявленных с использованием ключевого слова function, вместо этого сохраняется связанная с ними логика. Вот почему в приведенном ниже коде я поместил отладчик, чтобы остановить выполнение кода, как только мы достигнем строки 7, и, как вы можете видеть в области видимости, переменная country не определена, но в функции myCar хранятся некоторые значения. Это потому, что мы все еще находимся на первой фазе, фазе создания памяти, код еще не начал выполняться.

Теперь давайте перейдем ко второй фазе — фазе выполнения кода. Помните, что Java Script — синхронный язык программирования, поэтому он выполняет код последовательно, строка за строкой. Как и в первой фазе переменные и функции обрабатываются по-разному. Когда движок встречает переменную, он просто удаляет исходное значение, присвоенное переменной (undefined), и присваивает переменной значение, которое ей фактически было присвоено в коде. Теперь, когда дело доходит до функций, он справляется с этим совсем по-другому. Помните, что функции обычно представляют собой инкапсулированную логику, которую необходимо использовать повторно. Следовательно, многие вещи могут происходить внутри функции, такие как инициализация переменных, в которой Java-скрипт уже имеет заранее установленные методы работы с ней. Как вы думаете, что произойдет?

Итак, как упоминалось выше, сценарий Java уже имеет заранее установленные методы работы с такими вещами (глобальный контекст выполнения). Итак, здесь мы будем иметь дело с этим аналогичным образом, он создает другой контекст выполнения для обработки функции. Контекст выполнения будет работать точно так же, как глобальный контекст выполнения, имеющий фазу создания памяти и фазу выполнения кода, но он будет находиться внутри глобального контекста выполнения. Теперь вы можете задаться вопросом, а как насчет вложенных функций, механизм сценариев Java будет обрабатывать их так же, как и вложенные контексты выполнения. Потратьте некоторое время, чтобы визуализировать это. Лично я сделал с эскизом ниже. Испытайте себя и визуализируйте это по-другому. Не обращайте внимания на мой почерк 😂.

На предыдущем рисунке я просто показал вам результат на этапе создания памяти. Что ж, позвольте мне удалить отладчик, и я позволю коду работать, чтобы вы могли видеть.

Вот код, который я немного изменил, чтобы он выводил содержимое функции myCar().

Как и ожидалось, значение переменной country вернулось неопределенным, но функция фактически вернула присвоенное значение. Это связано с тем, как они по-разному обрабатываются на этапе создания памяти. Теперь давайте вызовем переменную после инициализации, после того как код для инициализации был запущен на этапе выполнения кода и переменной было присвоено ее значение.

Как мы видим, он выводит KENYA. Изменение положения, в котором я вызываю функцию, по-прежнему будет иметь тот же результат из-за того, как функции сохраняются на этапе создания памяти.

Теперь вы можете задаться вопросом, как сценарий Java управляет всеми этими контекстами выполнения в сценариях со сложным кодом. Это делается с помощью структуры данных, называемой стеком. В стеке сначала хранится глобальный контекст выполнения, а затем контексты выполнения функций. Он переключает их в память и из памяти. Как только программа контекстов выполнения завершена, она немедленно завершается и перемещается из стека вызовов.

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

Как вы можете видеть в выделенном разделе, у нас есть созданный глобальный контекст выполнения, он помечен как (анонимный). Теперь давайте поместим отладчик в функцию my car, чтобы поймать связанный с ней контекст выполнения прямо перед ее завершением.

Как вы можете видеть в выделенном разделе, вы можете видеть, что соответствующий стек вызовов был сформирован под названием myCar. Он вызывается сразу после вызова функции и завершается после завершения выполнения функции. Теперь, когда вы понимаете, что такое стек вызовов и как он работает, давайте изложим его так, чтобы его было легче представить, чтобы вы не застряли на собеседованиях. Стек вызовов — это структура данных, которую сценарий Java использует для управления вызовами функций. Вы также можете упомянуть, что он использует принцип LIFO (Last In First Out), согласно которому каждый контекст выполнения, возникающий в результате вызываемой функции, завершается раньше, чем предыдущие.

Это может показаться немного запутанным, но рассмотрите возможность добавления вложенной функции к функции, которую мы имели выше. Назовем его myPass(). Таким образом, когда код начнет выполняться, будет создан глобальный контекст выполнения, затем будет создан контекст выполнения myCar, и как только обработчик сценариев Java встретится с функцией myPass(), будет создан другой контекст выполнения. Но вот что функция myPass() должна быть автоматически запущена первой, чтобы функция myCar() также завершила свою работу. Затем, после того, как эти две функции будут выполнены, код также будет продолжать работать до завершения. Таким образом, их соответствующие контексты выполнения также ведут себя одинаково. Отсюда и принцип «последним пришел — первым вышел».

Спасибо за ваше время, я надеюсь, что вы поняли все хорошо. Если у вас есть какие-либо вопросы, не стесняйтесь обращаться. Удачного взлома!!