JavaScript | Оператор for-in, for-of, for-await-of

JavaScript | Оператор for-in, for-of, for-await-of

 

Синтаксис оператора for-in, for-of, for-await-of

ForInOfStatement [Yield, Await, Return] :

for ( [lookahead ≠ let [] LeftHandSideExpression [?Yield, ?Await] in Expression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

for ( var ForBinding [?Yield, ?Await] in Expression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

for ( ForDeclaration [?Yield, ?Await] in Expression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

for ( [lookahead ∉ { let, async of }] LeftHandSideExpression [?Yield, ?Await] of AssignmentExpression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

for ( var ForBinding [?Yield, ?Await] of AssignmentExpression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

for ( ForDeclaration [?Yield, ?Await] of AssignmentExpression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

[+Await] for await ( [lookahead ≠ let] LeftHandSideExpression [?Yield, ?Await] of AssignmentExpression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

[+Await] for await ( var ForBinding [?Yield, ?Await] of AssignmentExpression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

[+Await] for await ( ForDeclaration [?Yield, ?Await] of AssignmentExpression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

ForDeclaration [Yield, Await] :

LetOrConst ForBinding [?Yield, ?Await]

ForBinding [Yield, Await] :

BindingIdentifier [?Yield, ?Await]

BindingPattern [?Yield, ?Await]

 

Примечание

Этот раздел расширен Приложением B.3.6.

 

Статическая семантика: ранние ошибки

ForInOfStatement :

for ( LeftHandSideExpression in Expression ) Statement

for ( var ForBinding in Expression ) Statement

for ( ForDeclaration in Expression ) Statement

for ( LeftHandSideExpression of AssignmentExpression ) Statement

for ( var ForBinding of AssignmentExpression ) Statement

for ( ForDeclaration of AssignmentExpression ) Statement

for await ( LeftHandSideExpression of AssignmentExpression ) Statement

for await ( var ForBinding of AssignmentExpression ) Statement

for await ( ForDeclaration of AssignmentExpression ) Statement

 

Если IsLabelledFunction(Statement) истинно true, это синтаксическая ошибка.

 

Примечание

Это правило необходимо применять только в том случае, если реализовано расширение, указанное в разделе B.3.2.

 

ForInOfStatement :

for ( LeftHandSideExpression in Expression ) Statement

for ( LeftHandSideExpression of AssignmentExpression ) Statement

for await ( LeftHandSideExpression of AssignmentExpression ) Statement

Если LeftHandSideExpression является ObjectLiteral или ArrayLiteral, применяются следующие правила ранней ошибки:

Если LeftHandSideExpression не является ни ObjectLiteral, ни ArrayLiteral, применяется следующее правило ранней ошибки:

Это синтаксическая ошибка, если AssignmentTargetType для LeftHandSideExpression не является simple.

ForInOfStatement :

for ( ForDeclaration in Expression ) Statement

for ( ForDeclaration of AssignmentExpression ) Statement

for await ( ForDeclaration of AssignmentExpression ) Statement

  • Синтаксическая ошибка, если связанные имена BoundNames из ForDeclaration содержит «let».
  • Синтаксическая ошибка, если какой-либо элемент связанных имён BoundNames из ForDeclaration также встречается в VarDeclaredNames из Statement.
  • Если BoundNames из ForDeclaration содержит какие-либо повторяющиеся записи, это является синтаксической ошибкой.

 

Статическая семантика: IsDestructuring

MemberExpression : PrimaryExpression

1. Если PrimaryExpression является ObjectLiteral или ArrayLiteral, верните true.
2. Вернуть false.

MemberExpression :

MemberExpression [ Expression ]

MemberExpression . IdentifierName

MemberExpression TemplateLiteral

SuperProperty

MetaProperty

new MemberExpression Arguments

NewExpression :

new NewExpression

LeftHandSideExpression :

CallExpression

OptionalExpression

1. Вернуть false.

ForDeclaration : LetOrConst ForBinding

1. Вернуть IsDestructuring из ForBinding.

ForBinding : BindingIdentifier

1. Вернуть false.

ForBinding : BindingPattern

1. Вернуть true.
Примечание

Этот раздел расширен Приложением B.3.6.

 

Семантика среды выполнения: ForDeclarationBindingInitialization

С параметрами value и environment.

Примечание

undefined передается для среды environment, чтобы указать, что для присвоения значения инициализации следует использовать операцию PutValue. Так обстоит дело с операторами var и списками формальных параметров некоторых нестрогих функций (см. 10.2.10). В этих случаях лексическая привязка поднимается и преинициализируется до оценки ее инициализатора.

ForDeclaration : LetOrConst ForBinding

1. Верните результат выполнения BindingInitialization для ForBinding, передав значение value и среду environment в качестве аргументов.

 

Семантика среды выполнения: ForDeclarationBindingInstantiation

С параметром environment.

ForDeclaration : LetOrConst ForBinding

1. Утверждено: среда environment - это декларативная запись среды.
2. Для каждого элемента name из связанных имён BoundNames из ForBinding выполните
   a. Если IsConstantDeclaration из LetOrConst истинно true, то
      i. Выполнить ! environment.CreateImmutableBinding(name, true).
   b. Иначе,
      i. Выполнить ! environment.CreateMutableBinding(name, false).

 

Семантика времени выполнения: ForInOfLoopEvaluation

С параметром labelSet.

ForInOfStatement : for ( LeftHandSideExpression in Expression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
2. Вернуть ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResultenumerateassignmentlabelSet).

ForInOfStatement : for ( var ForBinding in Expression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
2. Вернуть ? ForIn/OfBodyEvaluation (ForBinding, Statement, keyResultenumeratevarBindinglabelSet).

ForInOfStatement : for ( ForDeclaration in Expression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, Expression, enumerate).
2. Вернуть ? ForIn/OfBodyEvaluation (ForDeclaration, Statement, keyResultenumeratelexicalBindinglabelSet).

ForInOfStatement : for ( LeftHandSideExpression of AssignmentExpression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
2. Вернуть ? ForIn/OfBodyEvaluation (LeftHandSideExpression, Statement, keyResultiterateassignmentlabelSet).

ForInOfStatement : for ( var ForBinding of AssignmentExpression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
2. Вернуть ? ForIn/OfBodyEvaluation (ForBinding, Statement, keyResultiteratevarBindinglabelSet).

ForInOfStatement : for ( ForDeclaration of AssignmentExpression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, iterate).
2. Вернуть ? ForIn/OfBodyEvaluation (ForDeclaration, Statement, keyResultiteratelexicalBindinglabelSet).

ForInOfStatement : for await ( LeftHandSideExpression of AssignmentExpression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(« », AssignmentExpression, async-iterate).
2. Вернуть ? ForIn/OfBodyEvaluation (LeftHandSideExpression, Statement, keyResultiterateassignmentlabelSetasync).

ForInOfStatement : for await ( var ForBinding of AssignmentExpression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(« », AssignmentExpression, async-iterate).
2. Вернуть ? ForIn/OfBodyEvaluation (ForBinding, Statement, keyResultiteratevarBindinglabelSetasync).

ForInOfStatement : for await ( ForDeclaration of AssignmentExpression ) Statement

1. Пусть keyResult будет ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, async-iterate).
2. Вернуть ? ForIn/OfBodyEvaluation (ForDeclaration, Statement, keyResultiteratelexicalBindinglabelSetasync).
Примечание

Этот раздел расширен Приложением B.3.6.

 

ForIn/OfHeadEvaluation ( uninitializedBoundNames, expr, iterationKind )

Абстрактная операция ForIn/OfHeadEvaluation принимает аргументы uninitializedBoundNames, expr и iterationKind (перечисление enumerate, итерация iterate или асинхронная итерация async-iterate). При вызове она выполняет следующие шаги:

1. Пусть oldEnv будет лексической средой (LexicalEnvironment) текущего контекста выполнения.
2. Если uninitializedBoundNames не является пустым Списком, тогда
   a. Утверждено: uninitializedBoundNames не имеет повторяющихся записей.
   b. Пусть newEnv будет NewDeclarativeEnvironment(oldEnv).
   c. Для каждого Строкового имени name из uninitializedBoundNames выполните
      i. Выполнить ! newEnv.CreateMutableBinding(name, false).
   d. Установите для лексической средой (LexicalEnvironment) текущего контекста выполнения значение newEnv.
3. Пусть exprRef будет результатом вычисления expr.
4. Установите для лексической средой (LexicalEnvironment) текущего контекста выполнения значение oldEnv.
5. Пусть exprValue будет ? GetValue(exprRef).
6. Если iterationKind перечислим (enumerate), то
   a. Если exprValue не определено или равно null, тогда
      i. Вернуть Completion { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.
   b. Пусть obj будет ! ToObject(exprValue).
   c. Пусть iterator будет ? EnumerateObjectProperties(obj).
   d. Пусть nextMethod будет ! GetV(iterator, "next").
   e. Вернуть запись Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
7. Иначе,
   a. Утверждено: iterationKind - это итерация iterate или асинхронная итерация async-iterate.
   b. Если iterationKind является асинхронным итерацией async-iterate, пусть iteratorHint будет асинхронным - async.
   c. В противном случае пусть iteratorHint будет синхронизированным sync.
   d. Вернуть ? GetIterator(exprValue, iteratorHint).

 

ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind, lhsKind, labelSet [ , iteratorKind ] )

Абстрактная операция ForIn/OfBodyEvaluation принимает аргументы lhs, stmt, iteratorRecord, iterationKind, lhsKind (либо присваивание assignment, либо varBinding, либо lexicalBinding), а также labelSet и необязательный аргумент iteratorKind (синхронный sync или асинхронный async). При вызове она выполняет следующие шаги:

1. Если iteratorKind отсутствует, установите для iteratorKind значение sync.
2. Пусть oldEnv будет LexicalEnvironment текущего контекста выполнения.
3. Пусть V будет undefined.
4. Пусть деструктуризация destructuring будет IsDestructuring из lhs.
5. Если деструктуризация destructuring является истинно true и если lhsKind является assignment (присваивается), то
a. Утверждение: lhs — это выражение LeftHandSideExpression.
b. Пусть assignmentPattern будет AssignmentPattern, который покрывается lhs.
6. Повторяйте,
a. Пусть nextResult будет ? вызовом Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
b. Если iteratorKind является асинхронным async, установите nextResult на ? Await(nextResult).
c. Если Type(nextResult) не является Object, выбросить исключение TypeError.
d. Пусть done будет ? IteratorComplete(nextResult).
e. Если done является true, вернуть NormalCompletion(V).
f. Пусть nextValue будет ? IteratorValue(nextResult).
g. Если lhsKind является либо assignment, либо varBinding, тогда
i. Если destructuring является false, тогда
1. Пусть lhsRef будет результатом вычисления lhs.(Это может быть оценено повторно.)
h. Иначе,
i. Утверждено: lhsKind — это lexicalBinding.
ii. Утверждено: lhs — это ForDeclaration.
iii. Пусть iterationEnv будет NewDeclarativeEnvironment(oldEnv).
iv. Выполнить ForDeclarationBindingInstantiation для lhs с передачей iterationEnv в качестве аргумента.
v. Установите для LexicalEnvironment текущего контекста выполнения значение iterationEnv.
vi. Если деструктуризация destructuring является false (ложна), то
1. Утверждено: lhs связывает одно имя.
2. Пусть lhsName будет единственным элементом из BoundNames из lhs.
3. Пусть lhsRef будет ! ResolveBinding(lhsName).
i. Если деструктуризация destructuring является false (ложна), то
i. Если lhsRef является внезапным завершением, то
1. Пусть status будет lhsRef.
ii. Иначе, если lhsKind является lexicalBinding, тогда
1. Пусть status будет InitializeReferencedBinding(lhsRef, nextValue).
iii. Иначе,
1. Пусть status будет PutValue(lhsRef, nextValue).
j. Иначе,
i. Если lhsKind является assignment (присваивание), тогда
1. Пусть status будет DestructuringAssignmentEvaluation для assignmentPattern с аргументом nextValue.
ii. Иначе, если lhsKind является varBinding, тогда
1. Утверждено: lhs является ForBinding.
2. Пусть status будет BindingInitialization lhs с аргументами nextValue и undefined.
iii. Иначе,
1. Утверждено: lhsKind — это lexicalBinding.
2. Утверждено: lhs — это ForDeclaration.
3. Пусть status будет ForDeclarationBindingInitialization из lhs с аргументами nextValue и iterationEnv.
k. Если status является внезапным завершением, тогда
i. Установите для LexicalEnvironment текущего контекста выполнения значение oldEnv.
ii. Если iteratorKind является асинхронным async, вернуть ? AsyncIteratorClose(iteratorRecord, status).
iii. Если iterationKind является enumerate (перечислим), то
1. Вернуть status
iv. Иначе,
1. Утверждено: iterationKind является iterate (итерируемым).
2. Возвращаться ? IteratorClose(iteratorRecord, status).
l. Пусть result будет результатом вычисления stmt.
m. Установите для LexicalEnvironment текущего контекста выполнения значение oldEnv.
n. Если LoopContinues(result, labelSet) ложно false, тогда
i. Если iterationKind является enumerate (перечислим), тогда
1. Вернуть завершение Completion(UpdateEmpty(result, V)).
ii. Иначе,
1. Утверждено: iterationKind является iterate (итерируемым).
2. Установите status UpdateEmpty(result, V).
3. Если iteratorKind является асинхронным async, вернуть? AsyncIteratorClose(iteratorRecord, status).
4. Вернуть ? IteratorClose(iteratorRecord, status).
o. Если result.[[Value]] не является empty (пустым), установите V равным result.[[Value]].

Семантика времени выполнения: оценка

ForBinding : BindingIdentifier

1. Пусть bindingId будет StringValue для BindingIdentifier.
2. Вернуть ? ResolveBinding(bindingId).

 

14.7.5.9 EnumerateObjectProperties ( O )

Абстрактная операция EnumerateObjectProperties принимает аргумент O (объект Object). При вызове она выполняет следующие шаги:

1. Утверждено: Type(O) - это объект.
2. Вернуть объект Iterator (27.1.1.2), метод next которого выполняет итерацию по всем ключам со значением String перечислимых (enumerable) свойств O. Объект итератора никогда не доступен напрямую для кода ECMAScript. Механика и порядок перечисления свойств не указаны, но должны соответствовать правилам, указанным ниже.

Методы throw и return итератора имеют значение null и никогда не вызываются. Метод next итератора обрабатывает свойства объекта, чтобы определить, должен ли ключ свойства возвращаться как значение итератора. Возвращённые ключи свойств не включают ключи, которые являются символами (Symbols). Свойства целевого объекта могут быть удалены во время перечисления. Свойство, которое удаляется до того, как оно будет обработано методом next итератора, игнорируется. Если новые свойства добавляются к целевому объекту во время перечисления, не гарантируется, что новые добавленные свойства будут обработаны в активном перечислении (active enumeration). Имя свойства будет возвращено методом next итератора не более одного раза в любом перечислении.

Перечисление свойств целевого объекта включает рекурсивное перечисление свойств его прототипа, прототипа прототипа и так далее; но свойство прототипа не обрабатывается, если оно имеет то же имя, что и свойство, которое уже было обработано методом next итератора. Значения атрибутов [[Enumerable]] не учитываются при определении того, было ли уже обработано свойство объекта-прототипа. Имена перечислимых свойств объектов-прототипов должны быть получены путем вызова EnumerateObjectProperties, передавая объект-прототип в качестве аргумента. EnumerateObjectProperties должен получить собственные ключи свойств целевого объекта, вызвав его внутренний метод [[OwnPropertyKeys]]. Атрибуты свойства целевого объекта должны быть получены путём вызова его внутреннего метода [[GetOwnProperty]].

Кроме того, если ни O, ни какой-либо объект в его цепочке прототипов не является экзотическим объектом Proxy, экзотическим объектом с целочисленным индексом, экзотическим объектом пространства имен модуля или реализацией, предоставленной экзотическим объектом, то итератор должен вести себя так же, как итератор, заданный CreateForInIterator(O) до тех пор, пока не произойдет одно из следующих событий:

  • значение внутреннего слота [[Prototype]] для O или объекта в его цепочке прототипов изменяется,
  • свойство удаляется из O или объекта в его цепочке прототипов,
  • свойство добавляется к объекту в цепочке прототипов O, или
  • значение атрибута [[Enumerable]] свойства объекта O или объекта в его цепочке прототипов изменяется.
Примечание 1

Реализации ECMAScript не требуются для реализации алгоритма из 14.7.5.10.2.1 напрямую. Они могут выбрать любую реализацию, поведение которой не будет отклоняться от этого алгоритма, если не нарушено одно из ограничений в предыдущем абзаце.

Ниже приводится информативное определение функции генератора ECMAScript, которая соответствует этим правилам:

function* EnumerateObjectProperties(obj) {
   const visited = new Set();
   for (const key of Reflect.ownKeys(obj)) {
      if (typeof key === "symbol") continue;
      const desc = Reflect.getOwnPropertyDescriptor(obj, key);
      if (desc) {
         visited.add(key);
         if (desc.enumerable) yield key;
      }
   }
   const proto = Reflect.getPrototypeOf(obj);
   if (proto === null) return;
   for (const protoKey of EnumerateObjectProperties(proto)) {
      if (!visited.has(protoKey)) yield protoKey;
   }
}
Примечание 2

Список экзотических объектов, для которых не требуется, чтобы реализации соответствовали CreateForInIterator, был выбран потому, что реализации исторически различались по поведению для этих случаев и согласовывались во всех остальных.

 

Объекты итератора For-In

Итератор For-In — это объект, который представляет определенную итерацию над некоторым конкретным объектом. Объекты For-In Iterator никогда не доступны напрямую коду ECMAScript; они существуют исключительно для иллюстрации поведения EnumerateObjectProperties.

CreateForInIterator ( object )

Абстрактная операция CreateForInIterator принимает аргумент object. Она используется для создания объекта For-In Iterator, который выполняет итерацию по собственным и унаследованным перечислимым строковым свойствам объекта object в определенном порядке. При вызове она выполняет следующие шаги:

1. Утверждено: Type(object) является Object.
2. Пусть iterator будет ! OrdinaryObjectCreate(%ForInIteratorPrototype%, « [[Object]], [[ObjectWasVisited]], [[VisitedKeys]], [[RemainingKeys]] »).
3. Установить iterator.[[Object]] на object.
4. Установить iterator.[[ObjectWasVisited]] на false.
5. Установить iterator.[[VisitedKeys]] на новый пустой список List.
6. Установить iterator.[[RemainingKeys]] на новый пустой список List.
7. Вернуть iterator.

 

The %ForInIteratorPrototype% Object

Объект %ForInIteratorPrototype%:

  • имеет свойства, которые наследуются всеми объектами For-In Iterator.
  • это обычный объект.
  • имеет внутренний слот [[Prototype]], значение которого %IteratorPrototype%.
  • никогда не доступен напрямую для кода ECMAScript.
  • обладает следующими свойствами:

%ForInIteratorPrototype%.next ( )

1. Пусть O будет значением этого this.
2. Утверждено: Type(O) является Object.
3. Утверждено: O имеет все внутренние слоты экземпляра For-In Iterator (14.7.5.10.3).
4. Пусть object будет O.[[Object]].
5. Пусть visited будет O.[[VisitedKeys]].
6. Пусть remaining будет O.[[RemainingKeys]].
7. Повторять,
   a. Если O.[[ObjectWasVisited]] является false, тогда
      i. Пусть keys будет ? object.[[OwnPropertyKeys]]().
      ii. Для каждого элемента key из keys, делать
         1. Если Type(key) является String, тогда
            a. Добавьте key к remaining.
      iii. Установить O.[[ObjectWasVisited]] на истину true.
   b. Повторяю, пока remaining не пусто,
      i. Пусть r будет первым из элементов remaining. (оставшихся)
      ii. Удалите первый элемент из remaining (оставшихся).
      iii. Если не существует элемента v из visited (посещенного), такого что SameValue(r, v) является true (истинно), тогда
         1. Пусть desc будет ? object.[[GetOwnProperty]](r).
         2. Если desc не является undefined, тогда
            a. Добавить r к visited.
            b. Если desc.[[Enumerable]] является истиной true, вернуть CreateIterResultObject(r, false).
   c. Установить object на ? object.[[GetPrototypeOf]]().
   d. Установить O.[[Object]] на object.
   e. Установить O.[[ObjectWasVisited]] на false.
   f. Если object является null, вернуть CreateIterResultObject(undefined, true).

 

Свойства экземпляров итератора For-In

Экземпляры For-In Iterator — это обычные объекты, наследующие свойства от внутреннего объекта %ForInIteratorPrototype%. Экземпляры For-In Iterator изначально создаются с внутренними слотами, перечисленными в Таблице 39.

Internal Slot (Внутренний слот) Описание
[[Object]] Значение объекта, свойства которого повторяются.
[[ObjectWasVisited]] Значение true, если итератор вызвал [[OwnPropertyKeys]] для [[Object]], в противном случае — false.
[[VisitedKeys]] Список значений String, которые были выданы этим итератором на данный момент.
[[RemainingKeys]] Список значений String, которые должны быть созданы для текущего объекта перед повторением свойств его прототипа (если его прототип не равен нулю).

Таблица 39: Внутренние слоты экземпляров итераторов For-In

 

 

Информационные ссылки

JavaScript | Зарезервированные слова (ReservedWord)

Стандарт ECMAScript — Раздел «12.6.2 Keywords and Reserved Words» — https://tc39.es/ecma262/#prod-ReservedWord

Алгоритмические обозначения

Условные обозначения

Стандарт ECMAScript — Раздел «14.7 Iteration Statements» — https://tc39.es/ecma262/#sec-iteration-statements