For Loops в спецификации EcmaScript

Я пытался как можно глубже понять, как работает javascript под капотом, и одновременно пытался изучить спецификацию. Меня немного смущает описание ForLoopEvaluation

Согласно спецификации:

ForStatement : for ( LexicalDeclaration Expressionopt; Expressionopt ) Оператор

  1. Пусть oldEnv будет running execution context's LexicalEnvironment.

  2. Пусть loopEnv будет NewDeclarativeEnvironment(oldEnv).

  3. Пусть isConst будет IsConstantDeclaration of LexicalDeclaration.

  4. ПустьboundNames будет BoundNames из LexicalDeclaration.

  5. Для каждого элемента dn изboundNames выполните

    а. Если isConst истинно, то я. Выполнять ! loopEnv.CreateImmutableBinding(dn, true).

    б. Еще, я. Выполнять ! loopEnv.CreateMutableBinding(dn, false).

  6. Установите для LexicalEnvironment текущего контекста выполнения значение loopEnv.

  7. Пусть forDcl будет завершением (вычислением лексического объявления).

  8. Если forDcl является внезапным завершением, то

    а. Задайте для LexicalEnvironment текущего контекста выполнения значение oldEnv.

    б. Возвращаться ? для Dcl.

  9. Если isConst ложно, пусть perIterationLets будетboundNames; в противном случае пусть perIterationLets будет новым пустым списком.

  10. Если присутствует первое Выражение, пусть test будет первым Выражением; в противном случае пусть test будет пустым.

  11. Если присутствует второе Выражение, пусть приращение будет вторым Выражением; в противном случае пусть приращение будет пустым.

  12. Пусть bodyResult будет Completion(ForBodyEvaluation(test, increment, Statement, perIterationLets, labelSet)).

  13. Задайте для LexicalEnvironment текущего контекста выполнения значение oldEnv.

  14. Возвращаться ? телоРезультат.

Теперь, если мы посмотрим на ForBodyEvaluation

14.7.4.3 ForBodyEvaluation (test, increment, stmt, perIterationBindings, labelSet)

Абстрактная операция ForBodyEvaluation принимает аргументы test (узел синтаксического анализа выражения или пустой), increment (узел синтаксического анализа выражения или пустой), stmt (узел синтаксического анализа оператора), perIterationBindings (список строк) и labelSet (список строк). и возвращает либо нормальное завершение, содержащее значение языка ECMAScript, либо резкое завершение. При вызове он выполняет следующие действия:

  1. Пусть V не определено.

  2. Выполнять ? CreatePerIterationEnvironment(perIterationBindings).

  3. Повторить,

    а. Если тест не пуст, то

    • Пусть testRef будет ? Оценка теста.
    • Пусть testValue будет ? ПолучитьЗначение(тестСсылка).
    • Если ToBoolean(testValue) ложно, вернуть V.

    б. Пусть результатом будет завершение (оценка stmt).

    в. Если LoopContinues(result, labelSet) ложно, вернуть ? UpdateEmpty(результат, V).

    д. Если result.[[Value]] не пусто, установите для V значение result.[[Value]].

    е. Выполнять ? CreatePerIterationEnvironment(perIterationBindings).

    ф. Если приращение не пусто, то я. Пусть incRef будет ? Оценка приращения. II. Выполнять ? ПолучитьЗначение(incRef).

Теперь, когда мы смотрим на CreatePerIterationEnvironment, он говорит следующее:

14.7.4.4 CreatePerIterationEnvironment ( perIterationBindings )

Абстрактная операция CreatePerIterationEnvironment принимает аргумент perIterationBindings (список строк) и возвращает либо обычное завершение, содержащее неиспользуемые, либо завершение броска. При вызове он выполняет следующие действия:

  1. Если у perIterationBindings есть какие-либо элементы, то

    а. Пусть lastIterationEnv будет LexicalEnvironment текущего контекста выполнения.

    б. Пусть внешним будет lastIterationEnv.[[OuterEnv]].

    в. Утверждение: внешний не равен нулю.

    д. Пусть thisIterationEnv будет NewDeclarativeEnvironment(outer).

    е. Для каждого элемента bn perIterationBindings выполните

    • Выполнять ! thisIterationEnv.CreateMutableBinding(bn, false).
    • Пусть lastValue будет ? lastIterationEnv.GetBindingValue(bn, true).
    • Выполнять ! thisIterationEnv.InitializeBinding(bn, lastValue).

    ф. Задайте для LexicalEnvironment текущего контекста выполнения значение thisIterationEnv.

  2. Возврат неиспользованного.

Я не понимаю, когда выполняется цикл for, поскольку функция не вызывается, новый контекст выполнения не создается. Почему здесь для обычного цикла for говорится, что если есть какие-либо perIterationBindings, то lastIterationEnvironment должен быть LexicalEnvironnment текущего контекста выполнения?

Я могу ошибаться, но связано ли это с возможным использованием оператора запятой, при котором используется функция получения? Это единственное объяснение, которое я могу придумать, оправдывающее использование термина контекст выполнения в контексте традиционного цикла for.

Это все в спецификации - tc39.es/ecma262/#sec-returnifabrupt-shorthands к сожалению до сих пор не понятно!

phuzi 08.06.2023 20:23

Вы пробовали копаться в реализациях JS? V8, SpiderMonkey, JCore, Hermes и т. д., если вы знаете С++, я предлагаю вам заглянуть туда, так как их работа - следовать спецификации до T

Undo 08.06.2023 20:50

Всегда есть работающий контекст выполнения, даже если функции нет. Ведь глобальный код тоже нужно как-то исполнять.

Felix Kling 08.06.2023 23:02
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
3
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это не имеет ничего общего с вызовами функций. Цикл for с лексическими привязками (let, const) создает новую область для каждой итерации — см. Объяснение `let` и область видимости блока с циклами for для получения более подробной информации.

В спецификации лексическая область видимости достигается путем создания вложенных записей декларативной среды. Самый внутренний из них, который активен в определенный момент во время выполнения, всегда сохраняется в LexicalEnvironment текущего контекста выполнения, он просто изменяется всякий раз, когда область действия входит или выходит из нее. Неважно, является ли контекст выполнения глобальным, созданным из вызова функции или чем-то другим.

Что касается lastIterationEnv, обратите внимание, что в первой итерации цикла (которая включает в себя первую оценку выражения test) lastIterationEnv — это loopEnv, которое было установлено в ForLoopEvaluation и в котором оператор LexicalDeclaration был оценен для инициализации переменных цикла. В последующих итерациях (если они есть) lastIterationEnv будет PerIterationEnvironment предыдущей итерации.

Я всегда рассматривал контекст выполнения как кадр стека вызовов, и когда выполняется цикл for, в стек вызовов не добавляется кадр. Правильно ли я говорю, что цикл for создает контекст выполнения, но не добавляется в стек вызовов?

dbzx10299 09.06.2023 05:11

Да, контекст выполнения — это кадр стека вызовов. Но нет, цикл for не создает новый фрейм и не добавляет его в стек вызовов, он просто изменяет фрейм, который находится на вершине стека (обратите внимание, что стек никогда не бывает пустым при выполнении кода, всегда есть как минимум глобальный контекст). Он создает только новые записи среды (области действия).

Bergi 09.06.2023 05:14

Оператор for в строке 1 говорит: «Пусть oldEnv будет LexicalEnvironment текущего контекста выполнения», в этом случае он должен ссылаться на глобальный контекст выполнения. Это была часть, в которой я был сбит с толку, хотя цикл for не создает новый контекст выполнения, всегда есть глобальный контекст выполнения, и это часть, которая изменяется.

dbzx10299 09.06.2023 05:19

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

Bergi 09.06.2023 05:41

Другие вопросы по теме