В этом посте мы обсудим, что такое контекст выполнения и цепочка областей видимости в JavaScript. Так же пошагово проверим внутреннюю работу JavaScript. Понимание этих концепций поможет не только понять внутреннее устройство JavaScript, но и другие концепции, такие как подъем и закрытие.

Контекст выполнения (EC) определяется как среда, в которой выполняется код JavaScript. Под средой я подразумеваю значения this, переменных, объектов и функций, к которым код JavaScript имеет доступ в определенное время.

Контекст выполнения в JavaScript бывает трех типов:

  1. Глобальный контекст выполнения (GEC): это контекст выполнения по умолчанию, в котором код JS начинает свое выполнение при первой загрузке файла в браузере. Весь глобальный код, то есть код, который не находится внутри какой-либо функции или объекта, выполняется внутри глобального контекста выполнения. GEC не может быть более одного, потому что для выполнения кода JS возможна только одна глобальная среда, поскольку механизм JS является однопоточным.
  2. Функциональный контекст выполнения (FEC): функциональный контекст выполнения определяется как контекст, создаваемый механизмом JS всякий раз, когда он обнаруживает какой-либо вызов функции. Каждая функция имеет собственный контекст выполнения. Их может быть больше одного. Функциональный контекст выполнения имеет доступ ко всему коду глобального контекста выполнения, хотя обратное не применимо. При выполнении кода глобального контекста выполнения, если движок JS обнаруживает вызов функции, он создает новый функциональный контекст выполнения для этой функции. В контексте браузера, если код выполняется в strict режиме, значение this равно undefined , иначе это window объект в контексте выполнения функции.
  3. Оценка: контекст выполнения внутри eval функции.

Стек контекста выполнения (ECS): Стек контекста выполнения - это структура данных стека, то есть структура данных последний пришел - первый вышел, для хранения всех стеков выполнения, созданных в течение жизненного цикла скрипта. Глобальный контекст выполнения по умолчанию присутствует в стеке контекстов выполнения и находится внизу стека. При выполнении кода глобального контекста выполнения, если движки JS находят вызов функции, они создают функциональный контекст выполнения для этой функции и помещают его поверх стека контекста выполнения. Механизм JS выполняет функцию, контекст выполнения которой находится наверху стека контекстов выполнения. После того, как весь код функции выполнен, движки JS извлекают контекст выполнения этой функции и начинают выполнение функции, которая находится под ним.

Давайте разберемся в этом на примере:

Как только приведенный выше код загружается в браузер, JS-движок помещает глобальный контекст выполнения в стек контекстов выполнения. Когда functionA вызывается из глобального контекста выполнения, механизм JS помещает functionA контекст выполнения в стек контекстов выполнения и начинает выполнение functionA.

Когда functionB вызывается из functionA контекста выполнения, механизм JS помещает functionB контекст выполнения в стек контекстов выполнения. Как только весь код functionB будет выполнен, JS-движок выскочит functionB контекст выполнения. После этого, когда контекст выполнения functionA находится на вершине стека контекстов выполнения, механизм JS начинает выполнение оставшегося кода functionA.

После выполнения всего кода из functionA движок JS извлекает functionA контекст выполнения из стека контекстов выполнения и начинает выполнение оставшегося кода из глобального контекста выполнения.

Когда весь код выполнен, JS-движок выдает глобальный контекст выполнения, и выполнение JavaScript завершается.

До сих пор мы обсуждали, как движок JavaScript обрабатывает контекст выполнения. Теперь посмотрим, как он создает контекст выполнения.

Движок JavaScript создает контекст выполнения в следующие два этапа:

  1. Фаза создания
  2. Фаза исполнения

Этап создания - это этап, на котором механизм JS вызвал функцию, но ее выполнение еще не началось. На этапе создания движок JS находится на этапе компиляции и просто просматривает код функции для компиляции кода, он не выполняет никакого кода.

На этапе создания движок JS выполняет следующую задачу:

  1. Создает объект активации или объект переменной: объект активации - это специальный объект в JS, который содержит все переменные, аргументы функций и информацию о декларации внутренних функций. Поскольку объект активации - это особый объект, он не имеет свойства dunder proto.
  2. Создает цепочку областей видимости: После создания объекта активации механизм JS инициализирует цепочку областей видимости, которая представляет собой список всех объектов переменных, внутри которых существует текущая функция. Это также включает переменный объект глобального контекста выполнения. Цепочка областей видимости также содержит текущий объект переменной функции.
  3. Определяет значение этого: После цепочки областей видимости механизм JavaScript инициализирует значение this .

Давайте разберемся, как движок JavaScript создает объект активации, на примере.

Сразу после вызова funA и до начала выполнения кода funA движок JS создает executonContextObj для funA, который можно представить, как показано ниже:

Объект активации или переменный объект содержит объект аргумента, который содержит подробную информацию об аргументах функции.

У него будет имя свойства для каждой из переменных и функций, объявленных внутри текущей функции. Объект активации или объект переменной в нашем случае будет таким, как показано ниже:

  1. ArgumentObject: движки JS создадут объект аргумента, как показано в приведенном выше коде. У него также будет свойство length, указывающее общее количество аргументов в функции. У него будет просто имя свойства, а не его значение.
  2. Теперь для каждой переменной в функции механизм JS создаст свойство для объекта активации или объекта переменной и инициализирует его с помощью undefined. Поскольку аргументы также являются переменными внутри функции, они также присутствуют как свойство объекта аргумента.
  3. Если переменная уже существует как свойство объекта аргумента, JS-движок ничего не сделает и перейдет к следующей строке.
  4. Когда движок JS встречает определение функции внутри текущей функции, он создает новое свойство по имени функции. Определения функций на этапе создания хранятся в динамической памяти, они не хранятся в стеке контекста выполнения. Свойство имени функции указывает на его определение в динамической памяти.

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

После этого JS-движки создадут цепочку областей видимости и определят значение this.

Этап выполнения:

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

После этапа исполнения объект переменной будет выглядеть так:

Полный пример:

Рассмотрим код ниже.

Когда приведенный выше код загружается в браузере, JS-движок переходит в фазу компиляции для создания исполняемых объектов. На этапе компиляции движок JS обрабатывает только объявления, не заботясь о значениях. Это этап создания контекста выполнения.

Строка 1: в этой строке переменной a присваивается значение 1, поэтому механизм JS не воспринимает это как объявление переменной или объявление функции, и она переместится в строку 3. Он ничего не делает с этой строкой на этапе компиляции, так как это не объявление.

Строка 3: поскольку приведенный выше код находится в глобальной области и является объявлением переменной, движки JS создадут свойство с именем этой переменной в глобальном объекте контекста выполнения и инициализируют его с помощью undefined значение.

Строка 5: движок JS находит объявление функции, поэтому он сохраняет определение функции в динамической памяти и создает свойство, указывающее на место, где хранится определение функции. Движок JS не знает, что находится внутри cFunc, он просто указывает на его местоположение.

Строка 18: этот код не является декларацией, поэтому движок JS ничего делать не будет.

Объект глобального контекста выполнения после этапа создания:

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

Строка 1: движки JS обнаруживают, что в объекте переменной нет свойства с именем a, поэтому он добавляет это свойство в глобальный контекст выполнения и инициализирует его значение равным 1. .

Строка 3: движки JS проверяют наличие свойства с именем b в объекте переменной и, следовательно, обновляют его значение до 2.

Строка 5: поскольку это объявление функции, оно ничего не делает и переходит к строке 18.

Объект глобального контекста выполнения после фазы выполнения:

Строка 18: здесь вызывается cFunc, поэтому механизм JS снова входит в фазу компиляции для создания объекта контекста выполнения cFunc путем его сканирования.

Поскольку cFunc имеет e в качестве аргумента, механизм JS добавит e в объект аргумента cFunc объекта контекста выполнения. и создайте свойство с именем e и инициализируйте его значением 2.

Строка 6: движок JS проверяет, является ли c свойством в объекте активации cFunc. Поскольку свойства с таким именем нет, он добавит c как свойство и инициализирует его значение равным undefined.

Строка 7: то же, что и строка 6.

Строка 9: поскольку эта строка не является декларацией, движок JS перейдет к следующей строке.

Строка 11: движок JS находит объявление функции, поэтому он сохраняет определение функции в памяти кучи и создает свойство dFunc , которое будет указывать на место, где находится определение функции. хранится. JS-движок не знает, что находится внутри dFunc.

cFunc объект контекста выполнения после фазы компиляции:

Строка 15: поскольку этот оператор не является декларацией, движок JS ничего делать не будет.

Поскольку в дальнейшем в этой функции нет строк, JS-движок перейдет в фазу выполнения и выполнит cFunc путем повторного сканирования.

Строки 6 и 7: c и d получают значения 10 и 15 соответственно.

Строка 9: поскольку a не является свойством cFunc объекта контекста выполнения и не является объявлением, механизм JS перейдет в глобальный контекст выполнения. с помощью цепочки областей видимости и проверяет, существует ли свойство с именем a в глобальном объекте контекста выполнения. Если свойство не существует, оно создаст новое и инициализирует его. Здесь, поскольку свойство с именем a уже существует в глобальном объекте контекста выполнения, оно обновит свое значение до 3 с 1. Движок JS переходит в глобальный контекст выполнения только в этом случае, т.е. когда он находит переменную на этапе выполнения, которая не является свойством текущего объекта контекста выполнения.

Строка 11: движки JS создадут свойство dFunc и укажут на его расположение в куче.

Объект контекста выполнения cFunc после фазы выполнения:

Строка 15: поскольку это вызов функции, движки JS снова войдут в фазу компиляции для создания dFunc объекта контекста выполнения.

dFunc объект контекста выполнения имеет доступ ко всем переменным и функциям, определенным в cFunc и в глобальной области с использованием цепочки областей видимости.

Точно так же cFunc имеет доступ ко всем переменным и объектам в глобальной области, но не имеет доступа к dFunc переменным и объектам.

Глобальный контекст выполнения не имеет доступа к cFunc или dFunc переменным или объектам.

Думаю, с помощью описанных выше концепций будет легко понять, как подъем работает в JavaScript.

Scope Chain

Цепочка областей видимости - это список всех переменных объектов функций, внутри которых существует текущая функция. Цепочка областей видимости также состоит из текущего объекта выполнения функции.

Рассмотрим приведенный ниже код:

Здесь, когда функция cFunc вызывается из глобального контекста выполнения, цепочка областей видимости cFunc будет выглядеть следующим образом

Scope chain of cFunc = [ cFunc variable object, 
                         Global Execution Context variable object]

Когда dFunc вызывается из cFunc, поскольку dFunc находится внутри cFunc, dFunc’s цепочка областей состоит из dFunc объекта переменных, cFunc объект переменной и объект переменной глобального контекста выполнения.

Scope chain of dFunc = [dFunc variable object, 
                        cFunc variable object,
                        Global execution context variable object]

Когда мы пытаемся получить доступ к f внутри dFunc, механизм JS проверяет, доступен ли f внутри dFunc’s объекта переменной. Если он находит значение f’s, это значение console.log f’s.

Когда мы пытаемся получить доступ к переменной c внутри dFunc, механизм JS проверяет, доступен ли c внутри объекта переменной dFunc’s. Если переменная недоступна, она переместится в cFunc объект переменной.

Поскольку переменная c недоступна внутри dFunc’s объекта переменной, JS-движки перемещаются в cFunc’s объект переменной. Поскольку c доступен для cFunc объекта переменной, он будет иметь console.log c’s значение.

Когда мы пытаемся зарегистрировать значение a’s внутри dFunc, JS-движки проверяют, доступен ли a внутри объекта переменной dFunc’s. Если a недоступен внутри объекта переменной dFunc , он переместится к следующему элементу в цепочке областей видимости, то есть к объекту переменной cFunc’s. Механизмы JS проверят, является ли cFunc’s объект переменной как переменная a. Здесь переменная a недоступна в cFunc’s объекте переменной, следовательно, она будет проверять следующие элементы в цепочке dFunc’s, то есть объект переменной глобального контекста выполнения . Здесь a доступен для dFunc’s объекта переменной, и он будет содержать значение a’ s .

Точно так же в случае cFunc механизм JS найдет значение переменной a’s из глобального объекта выполнения.

cFunc не знает, что переменная f существует. Следовательно, если мы попытаемся получить доступ к f из cFunc , это приведет к ошибке. Но функция dFunc имеет доступ к c и d переменной с использованием цепочки областей видимости.

Замыкания можно объяснить с помощью контекста цепочки областей видимости в JavaScript.

Если вам понравилась статья и вы хотите получать обновления о моих новых статьях, подпишитесь на меня в среде и в твиттере @ happyrupesh123

Другие статьи:

  1. Внутреннее устройство JavaScript: движок JavaScript, среда выполнения и веб-API setTimeout
  2. Понимание API веб-ресурсов
  3. Руководство по ReactJS для новичков
  4. Путешествие JavaScript: от загрузки сценария к выполнению
  5. Чем хороши прогрессивные веб-приложения и как их создать
  6. Давай получим это« это раз и навсегда»
  7. Работники сферы обслуживания
  8. Внедрение Service Workers
  9. Виртуальный DOM в ReactJS
  10. Прототипы в JavaScript
  11. ‘ This ’в JavaScript
  12. Object.create в JavaScript
  13. Наследование в JavaScript
  14. Создавать объекты на JavaScript
  15. Объекты в JavaScript
  16. Zip в Python
  17. Декораторы в Python
  18. Объединение двух списков в Python
  19. Лямбда, карта и фильтр в Python
  20. Составление списков в Python