# 14 ECMAScript Language: Statements and Declarations

## Syntax

Statement [Yield, Await, Return] : BlockStatement [?Yield, ?Await, ?Return] VariableStatement [?Yield, ?Await] EmptyStatement ExpressionStatement [?Yield, ?Await] IfStatement [?Yield, ?Await, ?Return] BreakableStatement [?Yield, ?Await, ?Return] ContinueStatement [?Yield, ?Await] BreakStatement [?Yield, ?Await] [+Return] ReturnStatement [?Yield, ?Await] WithStatement [?Yield, ?Await, ?Return] LabelledStatement [?Yield, ?Await, ?Return] ThrowStatement [?Yield, ?Await] TryStatement [?Yield, ?Await, ?Return] DebuggerStatement Declaration [Yield, Await] : HoistableDeclaration [?Yield, ?Await, ~Default] ClassDeclaration [?Yield, ?Await, ~Default] LexicalDeclaration [+In, ?Yield, ?Await] HoistableDeclaration [Yield, Await, Default] : FunctionDeclaration [?Yield, ?Await, ?Default] GeneratorDeclaration [?Yield, ?Await, ?Default] AsyncFunctionDeclaration [?Yield, ?Await, ?Default] AsyncGeneratorDeclaration [?Yield, ?Await, ?Default] BreakableStatement [Yield, Await, Return] : IterationStatement [?Yield, ?Await, ?Return] SwitchStatement [?Yield, ?Await, ?Return]

# 14.1 Statement Semantics

# 14.1.1 Runtime Semantics: Evaluation

HoistableDeclaration : GeneratorDeclaration AsyncFunctionDeclaration AsyncGeneratorDeclaration

1. Return empty.

HoistableDeclaration : FunctionDeclaration

1. Return ? Evaluation of FunctionDeclaration.

BreakableStatement : IterationStatement SwitchStatement

1. Let newLabelSet be a new empty List.
2. Return ? LabelledEvaluation of this BreakableStatement with argument newLabelSet.

# 14.2 Block

## Syntax

BlockStatement [Yield, Await, Return] : Block [?Yield, ?Await, ?Return] Block [Yield, Await, Return] : { StatementList [?Yield, ?Await, ?Return]opt } StatementList [Yield, Await, Return] : StatementListItem [?Yield, ?Await, ?Return] StatementList [?Yield, ?Await, ?Return] StatementListItem [?Yield, ?Await, ?Return] StatementListItem [Yield, Await, Return] : Statement [?Yield, ?Await, ?Return] Declaration [?Yield, ?Await]

# 14.2.1 Static Semantics: Early Errors

Block : { StatementList }

- It is a Syntax Error if the LexicallyDeclaredNames of StatementList contains any duplicate entries, unless the host is a web browser or otherwise supports Block-Level Function Declarations Web Legacy Compatibility Semantics, and both of the following conditions are true:

  - IsStrict(this production) is false.
  - The duplicate entries are only bound by FunctionDeclarations.
- It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList also occurs in the VarDeclaredNames of StatementList.

# 14.2.2 Runtime Semantics: Evaluation

Block : { }

1. Return empty.

Block : { StatementList }

1. Let oldEnv be the running execution context's LexicalEnvironment.
2. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
3. Perform BlockDeclarationInstantiation(StatementList, blockEnv).
4. Set the running execution context's LexicalEnvironment to blockEnv.
5. Let blockValue be Completion(Evaluation of StatementList).
6. Set the running execution context's LexicalEnvironment to oldEnv.
7. Return ? blockValue.

Note 1

No matter how control leaves the Block the LexicalEnvironment is always restored to its former state.

StatementList : StatementList StatementListItem

1. Let sl be ? Evaluation of StatementList.
2. Let s be Completion(Evaluation of StatementListItem).
3. Return ? UpdateEmpty(s, sl).

Note 2

The value of a StatementList is the value of the last value-producing item in the StatementList. For example, the following calls to the `eval` function all return the value 1:

    eval("1;;;;;")
    eval("1;{}")
    eval("1;var a;")

# 14.2.3 BlockDeclarationInstantiation ( code, env )

The abstract operation BlockDeclarationInstantiation takes arguments code (a Parse Node) and env (a Declarative Environment Record) and returns unused. code is the Parse Node corresponding to the body of the block. env is the Environment Record in which bindings are to be created.

Note

When a Block or CaseBlock is evaluated a new Declarative Environment Record is created and bindings for each block scoped variable, constant, function, or class declared in the block are instantiated in the Environment Record.

It performs the following steps when called:

1. Let declarations be the LexicallyScopedDeclarations of code.
2. Let privateEnv be the running execution context's PrivateEnvironment.
3. For each element d of declarations, do
   1. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
         1. Perform ! env.CreateImmutableBinding(dn, true).
      2. Else,
         1. Normative Optional
            If the host is a web browser or otherwise supports Block-Level Function Declarations Web Legacy Compatibility Semantics, then
            1. If ! env.HasBinding(dn) is false, then
               1. Perform ! env.CreateMutableBinding(dn, false).
         2. Else,
            1. Perform ! env.CreateMutableBinding(dn, false).
   2. If d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
      1. Let fn be the sole element of the BoundNames of d.
      2. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
      3. Normative Optional
         If the host is a web browser or otherwise supports Block-Level Function Declarations Web Legacy Compatibility Semantics, then
         1. If the binding for fn in env is an uninitialized binding, then
            1. Perform ! env.InitializeBinding(fn, fo).
         2. Else,
            1. Assert: d is a FunctionDeclaration.
            2. Perform ! env.SetMutableBinding(fn, fo, false).
      4. Else,
         1. Perform ! env.InitializeBinding(fn, fo).
4. Return unused.

# 14.3 Declarations and the Variable Statement

# 14.3.1 Let and Const Declarations

Note

`let` and `const` declarations define variables that are scoped to the running execution context's LexicalEnvironment. The variables are created when their containing Environment Record is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initializer is assigned the value of its Initializer's AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a `let` declaration does not have an Initializer the variable is assigned the value undefined when the LexicalBinding is evaluated.

## Syntax

LexicalDeclaration [In, Yield, Await] : LetOrConst BindingList [?In, ?Yield, ?Await] ; LetOrConst : let const BindingList [In, Yield, Await] : LexicalBinding [?In, ?Yield, ?Await] BindingList [?In, ?Yield, ?Await] , LexicalBinding [?In, ?Yield, ?Await] LexicalBinding [In, Yield, Await] : BindingIdentifier [?Yield, ?Await] Initializer [?In, ?Yield, ?Await]opt BindingPattern [?Yield, ?Await] Initializer [?In, ?Yield, ?Await]

# 14.3.1.1 Static Semantics: Early Errors

LexicalDeclaration : LetOrConst BindingList ;

- It is a Syntax Error if the BoundNames of BindingList contains "let".
- It is a Syntax Error if the BoundNames of BindingList contains any duplicate entries.

LexicalBinding : BindingIdentifier Initializer opt

- It is a Syntax Error if Initializer is not present and IsConstantDeclaration of the LexicalDeclaration containing this LexicalBinding is true.

# 14.3.1.2 Runtime Semantics: Evaluation

LexicalDeclaration : LetOrConst BindingList ;

1. Perform ? Evaluation of BindingList.
2. Return empty.

BindingList : BindingList , LexicalBinding

1. Perform ? Evaluation of BindingList.
2. Return ? Evaluation of LexicalBinding.

LexicalBinding : BindingIdentifier

1. Let lhs be ! ResolveBinding(StringValue of BindingIdentifier).
2. Perform ! InitializeReferencedBinding(lhs, undefined).
3. Return empty.

Note

A static semantics rule ensures that this form of LexicalBinding never occurs in a `const` declaration.

LexicalBinding : BindingIdentifier Initializer

1. Let bindingId be the StringValue of BindingIdentifier.
2. Let lhs be ! ResolveBinding(bindingId).
3. If IsAnonymousFunctionDefinition(Initializer) is true, then
   1. Let value be ? NamedEvaluation of Initializer with argument bindingId.
4. Else,
   1. Let rhs be ? Evaluation of Initializer.
   2. Let value be ? GetValue(rhs).
5. Perform ! InitializeReferencedBinding(lhs, value).
6. Return empty.

LexicalBinding : BindingPattern Initializer

1. Let rhs be ? Evaluation of Initializer.
2. Let value be ? GetValue(rhs).
3. Let env be the running execution context's LexicalEnvironment.
4. Return ? BindingInitialization of BindingPattern with arguments value and env.

# 14.3.2 Variable Statement

Note

A `var` statement declares variables that are scoped to the running execution context's VariableEnvironment. Var variables are created when their containing Environment Record is instantiated and are initialized to undefined when created. Within the scope of any VariableEnvironment a common BindingIdentifier may appear in more than one VariableDeclaration but those declarations collectively define only one variable. A variable defined by a VariableDeclaration with an Initializer is assigned the value of its Initializer's AssignmentExpression when the VariableDeclaration is executed, not when the variable is created.

## Syntax

VariableStatement [Yield, Await] : var VariableDeclarationList [+In, ?Yield, ?Await] ; VariableDeclarationList [In, Yield, Await] : VariableDeclaration [?In, ?Yield, ?Await] VariableDeclarationList [?In, ?Yield, ?Await] , VariableDeclaration [?In, ?Yield, ?Await] VariableDeclaration [In, Yield, Await] : BindingIdentifier [?Yield, ?Await] Initializer [?In, ?Yield, ?Await]opt BindingPattern [?Yield, ?Await] Initializer [?In, ?Yield, ?Await]

# 14.3.2.1 Runtime Semantics: Evaluation

VariableStatement : var VariableDeclarationList ;

1. Perform ? Evaluation of VariableDeclarationList.
2. Return empty.

VariableDeclarationList : VariableDeclarationList , VariableDeclaration

1. Perform ? Evaluation of VariableDeclarationList.
2. Return ? Evaluation of VariableDeclaration.

VariableDeclaration : BindingIdentifier

1. Return empty.

VariableDeclaration : BindingIdentifier Initializer

1. Let bindingId be the StringValue of BindingIdentifier.
2. Let lhs be ? ResolveBinding(bindingId).
3. If IsAnonymousFunctionDefinition(Initializer) is true, then
   1. Let value be ? NamedEvaluation of Initializer with argument bindingId.
4. Else,
   1. Let rhs be ? Evaluation of Initializer.
   2. Let value be ? GetValue(rhs).
5. Perform ? PutValue(lhs, value).
6. Return empty.

Note

If a VariableDeclaration is nested within a with statement and the BindingIdentifier in the VariableDeclaration is the same as a property name of the binding object of the with statement's Object Environment Record, then step 5 will assign value to the property instead of assigning to the VariableEnvironment binding of the Identifier.

VariableDeclaration : BindingPattern Initializer

1. Let rhs be ? Evaluation of Initializer.
2. Let rVal be ? GetValue(rhs).
3. Return ? BindingInitialization of BindingPattern with arguments rVal and undefined.

# 14.3.3 Destructuring Binding Patterns

## Syntax

BindingPattern [Yield, Await] : ObjectBindingPattern [?Yield, ?Await] ArrayBindingPattern [?Yield, ?Await] ObjectBindingPattern [Yield, Await] : { } { BindingRestProperty [?Yield, ?Await] } { BindingPropertyList [?Yield, ?Await] } { BindingPropertyList [?Yield, ?Await] , BindingRestProperty [?Yield, ?Await]opt } ArrayBindingPattern [Yield, Await] : [ Elision opt BindingRestElement [?Yield, ?Await]opt ] [ BindingElementList [?Yield, ?Await] ] [ BindingElementList [?Yield, ?Await] , Elision opt BindingRestElement [?Yield, ?Await]opt ] BindingRestProperty [Yield, Await] : ... BindingIdentifier [?Yield, ?Await] BindingPropertyList [Yield, Await] : BindingProperty [?Yield, ?Await] BindingPropertyList [?Yield, ?Await] , BindingProperty [?Yield, ?Await] BindingElementList [Yield, Await] : BindingElisionElement [?Yield, ?Await] BindingElementList [?Yield, ?Await] , BindingElisionElement [?Yield, ?Await] BindingElisionElement [Yield, Await] : Elision opt BindingElement [?Yield, ?Await] BindingProperty [Yield, Await] : SingleNameBinding [?Yield, ?Await] PropertyName [?Yield, ?Await] : BindingElement [?Yield, ?Await] BindingElement [Yield, Await] : SingleNameBinding [?Yield, ?Await] BindingPattern [?Yield, ?Await] Initializer [+In, ?Yield, ?Await]opt SingleNameBinding [Yield, Await] : BindingIdentifier [?Yield, ?Await] Initializer [+In, ?Yield, ?Await]opt BindingRestElement [Yield, Await] : ... BindingIdentifier [?Yield, ?Await] ... BindingPattern [?Yield, ?Await]

# 14.3.3.1 Runtime Semantics: PropertyBindingInitialization

The syntax-directed operation PropertyBindingInitialization takes arguments value (an ECMAScript language value) and environment (an Environment Record or undefined) and returns either a normal completion containing a List of property keys or an abrupt completion. It collects a list of all bound property names. It is defined piecewise over the following productions:

BindingPropertyList : BindingPropertyList , BindingProperty

1. Let boundNames be ? PropertyBindingInitialization of BindingPropertyList with arguments value and environment.
2. Let nextNames be ? PropertyBindingInitialization of BindingProperty with arguments value and environment.
3. Return the list-concatenation of boundNames and nextNames.

BindingProperty : SingleNameBinding

1. Let name be the sole element of the BoundNames of SingleNameBinding.
2. Perform ? KeyedBindingInitialization of SingleNameBinding with arguments value, environment, and name.
3. Return « name ».

BindingProperty : PropertyName : BindingElement

1. Let P be ? Evaluation of PropertyName.
2. Perform ? KeyedBindingInitialization of BindingElement with arguments value, environment, and P.
3. Return « P ».

# 14.3.3.2 Runtime Semantics: RestBindingInitialization

The syntax-directed operation RestBindingInitialization takes arguments value (an ECMAScript language value), environment (an Environment Record or undefined), and excludedNames (a List of property keys) and returns either a normal completion containing unused or an abrupt completion. It is defined piecewise over the following productions:

BindingRestProperty : ... BindingIdentifier

1. Let lhs be ? ResolveBinding(StringValue of BindingIdentifier, environment).
2. Let restObj be OrdinaryObjectCreate(%Object.prototype%).
3. Perform ? CopyDataProperties(restObj, value, excludedNames).
4. If environment is undefined, return ? PutValue(lhs, restObj).
5. Return ? InitializeReferencedBinding(lhs, restObj).

# 14.3.3.3 Runtime Semantics: KeyedBindingInitialization

The syntax-directed operation KeyedBindingInitialization takes arguments value (an ECMAScript language value), environment (an Environment Record or undefined), and propertyName (a property key) and returns either a normal completion containing unused or an abrupt completion.

Note

When undefined is passed for environment it indicates that a PutValue operation should be used to assign the initialization value. This is the case for formal parameter lists of non-strict functions. In that case the formal parameter bindings are preinitialized in order to deal with the possibility of multiple parameters with the same name.

It is defined piecewise over the following productions:

BindingElement : BindingPattern Initializer opt

1. Let v be ? GetV(value, propertyName).
2. If Initializer is present and v is undefined, then
   1. Let defaultValue be ? Evaluation of Initializer.
   2. Set v to ? GetValue(defaultValue).
3. Return ? BindingInitialization of BindingPattern with arguments v and environment.

SingleNameBinding : BindingIdentifier Initializer opt

1. Let bindingId be the StringValue of BindingIdentifier.
2. Let lhs be ? ResolveBinding(bindingId, environment).
3. Let v be ? GetV(value, propertyName).
4. If Initializer is present and v is undefined, then
   1. If IsAnonymousFunctionDefinition(Initializer) is true, then
      1. Set v to ? NamedEvaluation of Initializer with argument bindingId.
   2. Else,
      1. Let defaultValue be ? Evaluation of Initializer.
      2. Set v to ? GetValue(defaultValue).
5. If environment is undefined, return ? PutValue(lhs, v).
6. Return ? InitializeReferencedBinding(lhs, v).

# 14.4 Empty Statement

## Syntax

EmptyStatement : ;

# 14.4.1 Runtime Semantics: Evaluation

EmptyStatement : ;

1. Return empty.

# 14.5 Expression Statement

## Syntax

ExpressionStatement [Yield, Await] : [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }] Expression [+In, ?Yield, ?Await] ; Note

An ExpressionStatement cannot start with a U+007B (LEFT CURLY BRACKET) because that might make it ambiguous with a Block. An ExpressionStatement cannot start with the `function` or `class` keywords because that would make it ambiguous with a FunctionDeclaration, a GeneratorDeclaration, or a ClassDeclaration. An ExpressionStatement cannot start with `async function` because that would make it ambiguous with an AsyncFunctionDeclaration or a AsyncGeneratorDeclaration. An ExpressionStatement cannot start with the two token sequence `let [` because that would make it ambiguous with a `let` LexicalDeclaration whose first LexicalBinding was an ArrayBindingPattern.

# 14.5.1 Runtime Semantics: Evaluation

ExpressionStatement : Expression ;

1. Let exprRef be ? Evaluation of Expression.
2. Return ? GetValue(exprRef).

# 14.6 The `if` Statement

## Syntax

IfStatement [Yield, Await, Return] : if ( Expression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return] else Statement [?Yield, ?Await, ?Return] if ( Expression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return] [lookahead ≠ else] Note
The lookahead-restriction [lookahead ≠ `else`] resolves the classic "dangling else" problem in the usual way. That is, when the choice of associated `if` is otherwise ambiguous, the `else` is associated with the nearest (innermost) of the candidate `if`s

# 14.6.1 Static Semantics: Early Errors

IfStatement : if ( Expression ) Statement else Statement

- It is a Syntax Error if IsLabelledFunction(the first Statement) is true.
- It is a Syntax Error if IsLabelledFunction(the second Statement) is true.

IfStatement : if ( Expression ) Statement

- It is a Syntax Error if IsLabelledFunction(Statement) is true.

Note

It is only necessary to apply this rule if the extension specified in B.3.1 is implemented.

# 14.6.2 Runtime Semantics: Evaluation

IfStatement : if ( Expression ) Statement else Statement

1. Let exprRef be ? Evaluation of Expression.
2. Let exprValue be ToBoolean(? GetValue(exprRef)).
3. If exprValue is true, then
   1. Let stmtCompletion be Completion(Evaluation of the first Statement).
4. Else,
   1. Let stmtCompletion be Completion(Evaluation of the second Statement).
5. Return ? UpdateEmpty(stmtCompletion, undefined).

IfStatement : if ( Expression ) Statement

1. Let exprRef be ? Evaluation of Expression.
2. Let exprValue be ToBoolean(? GetValue(exprRef)).
3. If exprValue is false, return undefined.
4. Let stmtCompletion be Completion(Evaluation of Statement).
5. Return ? UpdateEmpty(stmtCompletion, undefined).

# 14.7 Iteration Statements

## Syntax

IterationStatement [Yield, Await, Return] : DoWhileStatement [?Yield, ?Await, ?Return] WhileStatement [?Yield, ?Await, ?Return] ForStatement [?Yield, ?Await, ?Return] ForInOfStatement [?Yield, ?Await, ?Return]

# 14.7.1 Semantics

# 14.7.1.1 LoopContinues ( completion, labelSet )

The abstract operation LoopContinues takes arguments completion (a Completion Record) and labelSet (a List of Strings) and returns a Boolean. It performs the following steps when called:

1. If completion is a normal completion, return true.
2. If completion is not a continue completion, return false.
3. If completion.[[Target]] is empty, return true.
4. If labelSet contains completion.[[Target]], return true.
5. Return false.

Note

Within the Statement part of an IterationStatement a ContinueStatement may be used to begin a new iteration.

# 14.7.1.2 Runtime Semantics: LoopEvaluation

The syntax-directed operation LoopEvaluation takes argument labelSet (a List of Strings) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

IterationStatement : DoWhileStatement

1. Return ? DoWhileLoopEvaluation of DoWhileStatement with argument labelSet.

IterationStatement : WhileStatement

1. Return ? WhileLoopEvaluation of WhileStatement with argument labelSet.

IterationStatement : ForStatement

1. Return ? ForLoopEvaluation of ForStatement with argument labelSet.

IterationStatement : ForInOfStatement

1. Return ? ForInOfLoopEvaluation of ForInOfStatement with argument labelSet.

# 14.7.2 The `do`-`while` Statement

## Syntax

DoWhileStatement [Yield, Await, Return] : do Statement [?Yield, ?Await, ?Return] while ( Expression [+In, ?Yield, ?Await] ) ;

# 14.7.2.1 Static Semantics: Early Errors

DoWhileStatement : do Statement while ( Expression ) ;

- It is a Syntax Error if IsLabelledFunction(Statement) is true.

Note

It is only necessary to apply this rule if the extension specified in B.3.1 is implemented.

# 14.7.2.2 Runtime Semantics: DoWhileLoopEvaluation

The syntax-directed operation DoWhileLoopEvaluation takes argument labelSet (a List of Strings) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

DoWhileStatement : do Statement while ( Expression ) ;

1. Let V be undefined.
2. Repeat,
   1. Let stmtResult be Completion(Evaluation of Statement).
   2. If LoopContinues(stmtResult, labelSet) is false, return ? UpdateEmpty(stmtResult, V).
   3. If stmtResult.[[Value]] is not empty, set V to stmtResult.[[Value]].
   4. Let exprRef be ? Evaluation of Expression.
   5. Let exprValue be ? GetValue(exprRef).
   6. If ToBoolean(exprValue) is false, return V.

# 14.7.3 The `while` Statement

## Syntax

WhileStatement [Yield, Await, Return] : while ( Expression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return]

# 14.7.3.1 Static Semantics: Early Errors

WhileStatement : while ( Expression ) Statement

- It is a Syntax Error if IsLabelledFunction(Statement) is true.

Note

It is only necessary to apply this rule if the extension specified in B.3.1 is implemented.

# 14.7.3.2 Runtime Semantics: WhileLoopEvaluation

The syntax-directed operation WhileLoopEvaluation takes argument labelSet (a List of Strings) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

WhileStatement : while ( Expression ) Statement

1. Let V be undefined.
2. Repeat,
   1. Let exprRef be ? Evaluation of Expression.
   2. Let exprValue be ? GetValue(exprRef).
   3. If ToBoolean(exprValue) is false, return V.
   4. Let stmtResult be Completion(Evaluation of Statement).
   5. If LoopContinues(stmtResult, labelSet) is false, return ? UpdateEmpty(stmtResult, V).
   6. If stmtResult.[[Value]] is not empty, set V to stmtResult.[[Value]].

# 14.7.4 The `for` Statement

## Syntax

ForStatement [Yield, Await, Return] : for ( [lookahead ≠ let [] Expression [~In, ?Yield, ?Await]opt ; Expression [+In, ?Yield, ?Await]opt ; Expression [+In, ?Yield, ?Await]opt ) Statement [?Yield, ?Await, ?Return] for ( var VariableDeclarationList [~In, ?Yield, ?Await] ; Expression [+In, ?Yield, ?Await]opt ; Expression [+In, ?Yield, ?Await]opt ) Statement [?Yield, ?Await, ?Return] for ( LexicalDeclaration [~In, ?Yield, ?Await] Expression [+In, ?Yield, ?Await]opt ; Expression [+In, ?Yield, ?Await]opt ) Statement [?Yield, ?Await, ?Return]

# 14.7.4.1 Static Semantics: Early Errors

ForStatement : for ( Expression opt ; Expression opt ; Expression opt ) Statement for ( var VariableDeclarationList ; Expression opt ; Expression opt ) Statement for ( LexicalDeclaration Expression opt ; Expression opt ) Statement

- It is a Syntax Error if IsLabelledFunction(Statement) is true.

Note

It is only necessary to apply this rule if the extension specified in B.3.1 is implemented.

ForStatement : for ( LexicalDeclaration Expression opt ; Expression opt ) Statement

- It is a Syntax Error if any element of the BoundNames of LexicalDeclaration also occurs in the VarDeclaredNames of Statement.

# 14.7.4.2 Runtime Semantics: ForLoopEvaluation

The syntax-directed operation ForLoopEvaluation takes argument labelSet (a List of Strings) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

ForStatement : for ( Expression opt ; Expression opt ; Expression opt ) Statement

1. If the first Expression is present, then
   1. Let exprRef be ? Evaluation of the first Expression.
   2. Perform ? GetValue(exprRef).
2. If the second Expression is present, let test be the second Expression; else let test be empty.
3. If the third Expression is present, let increment be the third Expression; else let increment be empty.
4. Return ? ForBodyEvaluation(test, increment, Statement, « », labelSet).

ForStatement : for ( var VariableDeclarationList ; Expression opt ; Expression opt ) Statement

1. Perform ? Evaluation of VariableDeclarationList.
2. If the first Expression is present, let test be the first Expression; else let test be empty.
3. If the second Expression is present, let increment be the second Expression; else let increment be empty.
4. Return ? ForBodyEvaluation(test, increment, Statement, « », labelSet).

ForStatement : for ( LexicalDeclaration Expression opt ; Expression opt ) Statement

1. Let oldEnv be the running execution context's LexicalEnvironment.
2. Let loopEnv be NewDeclarativeEnvironment(oldEnv).
3. Let isConst be IsConstantDeclaration of LexicalDeclaration.
4. Let boundNames be the BoundNames of LexicalDeclaration.
5. For each element dn of boundNames, do
   1. If isConst is true, then
      1. Perform ! loopEnv.CreateImmutableBinding(dn, true).
   2. Else,
      1. Perform ! loopEnv.CreateMutableBinding(dn, false).
6. Set the running execution context's LexicalEnvironment to loopEnv.
7. Let forDcl be Completion(Evaluation of LexicalDeclaration).
8. If forDcl is an abrupt completion, then
   1. Set the running execution context's LexicalEnvironment to oldEnv.
   2. Return ? forDcl.
9. If isConst is false, let perIterationLets be boundNames; else let perIterationLets be a new empty List.
10. If the first Expression is present, let test be the first Expression; else let test be empty.
11. If the second Expression is present, let increment be the second Expression; else let increment be empty.
12. Let bodyResult be Completion(ForBodyEvaluation(test, increment, Statement, perIterationLets, labelSet)).
13. Set the running execution context's LexicalEnvironment to oldEnv.
14. Return ? bodyResult.

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

The abstract operation ForBodyEvaluation takes arguments test (an Expression Parse Node or empty), increment (an Expression Parse Node or empty), stmt (a Statement Parse Node), perIterationBindings (a List of Strings), and labelSet (a List of Strings) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It performs the following steps when called:

1. Let V be undefined.
2. Perform ? CreatePerIterationEnvironment(perIterationBindings).
3. Repeat,
   1. If test is not empty, then
      1. Let testRef be ? Evaluation of test.
      2. Let testValue be ? GetValue(testRef).
      3. If ToBoolean(testValue) is false, return V.
   2. Let result be Completion(Evaluation of stmt).
   3. If LoopContinues(result, labelSet) is false, return ? UpdateEmpty(result, V).
   4. If result.[[Value]] is not empty, set V to result.[[Value]].
   5. Perform ? CreatePerIterationEnvironment(perIterationBindings).
   6. If increment is not empty, then
      1. Let incRef be ? Evaluation of increment.
      2. Perform ? GetValue(incRef).

# 14.7.4.4 CreatePerIterationEnvironment ( perIterationBindings )

The abstract operation CreatePerIterationEnvironment takes argument perIterationBindings (a List of Strings) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

1. If perIterationBindings has any elements, then
   1. Let lastIterationEnv be the running execution context's LexicalEnvironment.
   2. Let outer be lastIterationEnv.[[OuterEnv]].
   3. Assert: outer is not null.
   4. Let thisIterationEnv be NewDeclarativeEnvironment(outer).
   5. For each element bn of perIterationBindings, do
      1. Perform ! thisIterationEnv.CreateMutableBinding(bn, false).
      2. Let lastValue be ? lastIterationEnv.GetBindingValue(bn, true).
      3. Perform ! thisIterationEnv.InitializeBinding(bn, lastValue).
   6. Set the running execution context's LexicalEnvironment to thisIterationEnv.
2. Return unused.

# 14.7.5 The `for`-`in`, `for`-`of`, and `for`-`await`-`of` Statements

## Syntax

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] Note

This section is extended by Annex B.3.5.

# 14.7.5.1 Static Semantics: Early Errors

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

- It is a Syntax Error if IsLabelledFunction(Statement) is true.

Note

It is only necessary to apply this rule if the extension specified in B.3.1 is implemented.

ForInOfStatement : for ( LeftHandSideExpression in Expression ) Statement for ( LeftHandSideExpression of AssignmentExpression ) Statement for await ( LeftHandSideExpression of AssignmentExpression ) Statement

- If LeftHandSideExpression is either an ObjectLiteral or an ArrayLiteral, LeftHandSideExpression must cover an AssignmentPattern.
- If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, it is a Syntax Error if the AssignmentTargetType of LeftHandSideExpression is invalid.

ForInOfStatement : for ( ForDeclaration in Expression ) Statement for ( ForDeclaration of AssignmentExpression ) Statement for await ( ForDeclaration of AssignmentExpression ) Statement

- It is a Syntax Error if the BoundNames of ForDeclaration contains "let".
- It is a Syntax Error if any element of the BoundNames of ForDeclaration also occurs in the VarDeclaredNames of Statement.
- It is a Syntax Error if the BoundNames of ForDeclaration contains any duplicate entries.

# 14.7.5.2 Static Semantics: IsDestructuring

The syntax-directed operation IsDestructuring takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

MemberExpression : PrimaryExpression

1. If PrimaryExpression is either an ObjectLiteral or an ArrayLiteral, return true.
2. Return false.

MemberExpression : MemberExpression [ Expression ] MemberExpression . IdentifierName MemberExpression TemplateLiteral SuperProperty MetaProperty new MemberExpression Arguments MemberExpression . PrivateIdentifier NewExpression : new NewExpression LeftHandSideExpression : CallExpression OptionalExpression

1. Return false.

ForDeclaration : LetOrConst ForBinding

1. Return IsDestructuring of ForBinding.

ForBinding : BindingIdentifier

1. Return false.

ForBinding : BindingPattern

1. Return true.

Note

This section is extended by Annex B.3.5.

# 14.7.5.3 Runtime Semantics: ForDeclarationBindingInitialization

The syntax-directed operation ForDeclarationBindingInitialization takes arguments value (an ECMAScript language value) and environment (an Environment Record or undefined) and returns either a normal completion containing unused or an abrupt completion.

Note

undefined is passed for environment to indicate that a PutValue operation should be used to assign the initialization value. This is the case for `var` statements and the formal parameter lists of some non-strict functions (see 10.2.11). In those cases a lexical binding is hoisted and preinitialized prior to evaluation of its initializer.

It is defined piecewise over the following productions:

ForDeclaration : LetOrConst ForBinding

1. Return ? BindingInitialization of ForBinding with arguments value and environment.

# 14.7.5.4 Runtime Semantics: ForDeclarationBindingInstantiation

The syntax-directed operation ForDeclarationBindingInstantiation takes argument environment (a Declarative Environment Record) and returns unused. It is defined piecewise over the following productions:

ForDeclaration : LetOrConst ForBinding

1. For each element name of the BoundNames of ForBinding, do
   1. If IsConstantDeclaration of LetOrConst is true, then
      1. Perform ! environment.CreateImmutableBinding(name, true).
   2. Else,
      1. Perform ! environment.CreateMutableBinding(name, false).
2. Return unused.

# 14.7.5.5 Runtime Semantics: ForInOfLoopEvaluation

The syntax-directed operation ForInOfLoopEvaluation takes argument labelSet (a List of Strings) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

ForInOfStatement : for ( LeftHandSideExpression in Expression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, enumerate, assignment, labelSet).

ForInOfStatement : for ( var ForBinding in Expression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, enumerate, var-binding, labelSet).

ForInOfStatement : for ( ForDeclaration in Expression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, Expression, enumerate).
2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, enumerate, lexical-binding, labelSet).

ForInOfStatement : for ( LeftHandSideExpression of AssignmentExpression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, iterate, assignment, labelSet).

ForInOfStatement : for ( var ForBinding of AssignmentExpression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, iterate, var-binding, labelSet).

ForInOfStatement : for ( ForDeclaration of AssignmentExpression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, iterate).
2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, iterate, lexical-binding, labelSet).

ForInOfStatement : for await ( LeftHandSideExpression of AssignmentExpression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, async-iterate).
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, iterate, assignment, labelSet, async).

ForInOfStatement : for await ( var ForBinding of AssignmentExpression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(« », AssignmentExpression, async-iterate).
2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, iterate, var-binding, labelSet, async).

ForInOfStatement : for await ( ForDeclaration of AssignmentExpression ) Statement

1. Let keyResult be ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, async-iterate).
2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, iterate, lexical-binding, labelSet, async).

Note

This section is extended by Annex B.3.5.

# 14.7.5.6 ForIn/OfHeadEvaluation ( uninitializedBoundNames, expr, iterationKind )

The abstract operation ForIn/OfHeadEvaluation takes arguments uninitializedBoundNames (a List of Strings), expr (an Expression Parse Node or an AssignmentExpression Parse Node), and iterationKind (enumerate, iterate, or async-iterate) and returns either a normal completion containing an Iterator Record or an abrupt completion. It performs the following steps when called:

1. Let oldEnv be the running execution context's LexicalEnvironment.
2. If uninitializedBoundNames is not empty, then
   1. Assert: uninitializedBoundNames has no duplicate entries.
   2. Let newEnv be NewDeclarativeEnvironment(oldEnv).
   3. For each String name of uninitializedBoundNames, do
      1. Perform ! newEnv.CreateMutableBinding(name, false).
   4. Set the running execution context's LexicalEnvironment to newEnv.
3. Let exprRef be Completion(Evaluation of expr).
4. Set the running execution context's LexicalEnvironment to oldEnv.
5. Let exprValue be ? GetValue(? exprRef).
6. If iterationKind is enumerate, then
   1. If exprValue is either undefined or null, then
      1. Return Completion Record { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.
   2. Let obj be ! ToObject(exprValue).
   3. Let iterator be EnumerateObjectProperties(obj).
   4. Let nextMethod be ! GetV(iterator, "next").
   5. Return the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
7. Assert: iterationKind is either iterate or async-iterate.
8. If iterationKind is async-iterate, let iteratorKind be async.
9. Else, let iteratorKind be sync.
10. Return ? GetIterator(exprValue, iteratorKind).

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

The abstract operation ForIn/OfBodyEvaluation takes arguments lhs (a Parse Node), stmt (a Statement Parse Node), iteratorRecord (an Iterator Record), iterationKind (enumerate or iterate), lhsKind (assignment, var-binding, or lexical-binding), and labelSet (a List of Strings) and optional argument iteratorKind (sync or async) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It performs the following steps when called:

1. If iteratorKind is not present, set iteratorKind to sync.
2. Let oldEnv be the running execution context's LexicalEnvironment.
3. Let V be undefined.
4. Let destructuring be IsDestructuring of lhs.
5. If destructuring is true and lhsKind is assignment, then
   1. Assert: lhs is a LeftHandSideExpression.
   2. Let assignmentPattern be the AssignmentPattern that is covered by lhs.
6. Repeat,
   1. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
   2. If iteratorKind is async, set nextResult to ? Await(nextResult).
   3. If nextResult is not an Object, throw a TypeError exception.
   4. Let done be ? IteratorComplete(nextResult).
   5. If done is true, return V.
   6. Let nextValue be ? IteratorValue(nextResult).
   7. If lhsKind is either assignment or var-binding, then
      1. If destructuring is true, then
         1. If lhsKind is assignment, then
            1. Let status be Completion(DestructuringAssignmentEvaluation of assignmentPattern with argument nextValue).
         2. Else,
            1. Assert: lhsKind is var-binding.
            2. Assert: lhs is a ForBinding.
            3. Let status be Completion(BindingInitialization of lhs with arguments nextValue and undefined).
      2. Else,
         1. Let lhsRef be Completion(Evaluation of lhs). (It may be evaluated repeatedly.)
         2. If lhsKind is assignment and the AssignmentTargetType of lhs is web-compat, throw a ReferenceError exception.
         3. If lhsRef is an abrupt completion, then
            1. Let status be lhsRef.
         4. Else,
            1. Let status be Completion(PutValue(lhsRef.[[Value]], nextValue)).
   8. Else,
      1. Assert: lhsKind is lexical-binding.
      2. Assert: lhs is a ForDeclaration.
      3. Let iterationEnv be NewDeclarativeEnvironment(oldEnv).
      4. Perform ForDeclarationBindingInstantiation of lhs with argument iterationEnv.
      5. Set the running execution context's LexicalEnvironment to iterationEnv.
      6. If destructuring is true, then
         1. Let status be Completion(ForDeclarationBindingInitialization of lhs with arguments nextValue and iterationEnv).
      7. Else,
         1. Assert: lhs binds a single name.
         2. Let lhsName be the sole element of the BoundNames of lhs.
         3. Let lhsRef be ! ResolveBinding(lhsName).
         4. Let status be Completion(InitializeReferencedBinding(lhsRef, nextValue)).
   9. If status is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to oldEnv.
      2. If iterationKind is enumerate, return ? status.
      3. Assert: iterationKind is iterate.
      4. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
      5. Return ? IteratorClose(iteratorRecord, status).
   10. Let result be Completion(Evaluation of stmt).
   11. Set the running execution context's LexicalEnvironment to oldEnv.
   12. If LoopContinues(result, labelSet) is false, then
       1. Set status to Completion(UpdateEmpty(result, V)).
       2. If iterationKind is enumerate, return ? status.
       3. Assert: iterationKind is iterate.
       4. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
       5. Return ? IteratorClose(iteratorRecord, status).
   13. If result.[[Value]] is not empty, set V to result.[[Value]].

# 14.7.5.8 Runtime Semantics: Evaluation

BindingIdentifier : Identifier yield await

1. Let bindingId be the StringValue of BindingIdentifier.
2. Return ? ResolveBinding(bindingId).

# 14.7.5.9 EnumerateObjectProperties ( O )

The abstract operation EnumerateObjectProperties takes argument O (an Object) and returns an iterator object. It performs the following steps when called:

1. Return an iterator object whose `next` method iterates over all the String-valued keys of enumerable properties of O. The iterator object is never directly accessible to ECMAScript code. The mechanics and order of enumerating the properties is not specified but must conform to the rules specified below.

The iterator's `throw` and `return` methods are null and are never invoked. The iterator's `next` method processes object properties to determine whether the property key should be returned as an iterator value. Returned property keys do not include keys that are Symbols. Properties of the target object may be deleted during enumeration. A property that is deleted before it is processed by the iterator's `next` method is ignored. If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration. A property name will be returned by the iterator's `next` method at most once in any enumeration.

Enumerating the properties of the target object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively; but a property of a prototype is not processed if it has the same name as a property that has already been processed by the iterator's `next` method. The values of [[Enumerable]] attributes are not considered when determining if a property of a prototype object has already been processed. The enumerable property names of prototype objects must be obtained by invoking EnumerateObjectProperties passing the prototype object as the argument. EnumerateObjectProperties must obtain the own property keys of the target object by calling its [[OwnPropertyKeys]] internal method. Property attributes of the target object must be obtained by calling its [[GetOwnProperty]] internal method.

In addition, if neither O nor any object in its prototype chain is a Proxy exotic object, TypedArray, module namespace exotic object, or implementation provided exotic object, then the iterator must behave as would the iterator given by CreateForInIterator(O) until one of the following occurs:

- the value of the [[Prototype]] internal slot of O or an object in its prototype chain changes,
- a property is removed from O or an object in its prototype chain,
- a property is added to an object in O's prototype chain, or
- the value of the [[Enumerable]] attribute of a property of O or an object in its prototype chain changes.

Note 1

ECMAScript implementations are not required to implement the algorithm in 14.7.5.10.2.1 directly. They may choose any implementation whose behaviour will not deviate from that algorithm unless one of the constraints in the previous paragraph is violated.

The following is an informative definition of an ECMAScript generator function that conforms to these rules:

    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;
      }
    }

Note 2
The list of exotic objects for which implementations are not required to match CreateForInIterator was chosen because implementations historically differed in behaviour for those cases, and agreed in all others.

# 14.7.5.10 For-In Iterator Objects

A For-In Iterator is an object that represents a specific iteration over some specific object. For-In Iterator objects are never directly accessible to ECMAScript code; they exist solely to illustrate the behaviour of EnumerateObjectProperties.

# 14.7.5.10.1 CreateForInIterator ( object )

The abstract operation CreateForInIterator takes argument object (an Object) and returns a For-In Iterator. It is used to create a For-In Iterator object which iterates over the own and inherited enumerable string properties of object in a specific order. It performs the following steps when called:

1. Let iterator be OrdinaryObjectCreate(%ForInIteratorPrototype%, « [[Object]], [[ObjectWasVisited]], [[VisitedKeys]], [[RemainingKeys]] »).
2. Set iterator.[[Object]] to object.
3. Set iterator.[[ObjectWasVisited]] to false.
4. Set iterator.[[VisitedKeys]] to a new empty List.
5. Set iterator.[[RemainingKeys]] to a new empty List.
6. Return iterator.

# 14.7.5.10.2 The %ForInIteratorPrototype% Object

The %ForInIteratorPrototype% object:

- has properties that are inherited by all For-In Iterator objects.
- is an ordinary object.
- has a [[Prototype]] internal slot whose value is %Iterator.prototype%.
- is never directly accessible to ECMAScript code.
- has the following properties:

# 14.7.5.10.2.1 %ForInIteratorPrototype%.next ( )

1. Let O be the this value.
2. Assert: O is an Object.
3. Assert: O has all of the internal slots of a For-In Iterator instance (14.7.5.10.3).
4. Let object be O.[[Object]].
5. Repeat,
   1. If O.[[ObjectWasVisited]] is false, then
      1. Let keys be ? object.[[OwnPropertyKeys]]().
      2. For each element key of keys, do
         1. If key is a String, then
            1. Append key to O.[[RemainingKeys]].
      3. Set O.[[ObjectWasVisited]] to true.
   2. Repeat, while O.[[RemainingKeys]] is not empty,
      1. Let r be the first element of O.[[RemainingKeys]].
      2. Remove the first element from O.[[RemainingKeys]].
      3. If O.[[VisitedKeys]] does not contain r, then
         1. Let desc be ? object.[[GetOwnProperty]](r).
         2. If desc is not undefined, then
            1. Append r to O.[[VisitedKeys]].
            2. If desc.[[Enumerable]] is true, return CreateIteratorResultObject(r, false).
   3. Set object to ? object.[[GetPrototypeOf]]().
   4. Set O.[[Object]] to object.
   5. Set O.[[ObjectWasVisited]] to false.
   6. If object is null, return CreateIteratorResultObject(undefined, true).

# 14.7.5.10.3 Properties of For-In Iterator Instances

For-In Iterator instances are ordinary objects that inherit properties from the %ForInIteratorPrototype% intrinsic object. For-In Iterator instances are initially created with the internal slots listed in Table 33.

Table 33: Internal Slots of For-In Iterator Instances

Internal Slot | Type | Description
--- | --- | ---
[[Object]] | an Object | The Object value whose properties are being iterated.
[[ObjectWasVisited]] | a Boolean | true if the iterator has invoked [[OwnPropertyKeys]] on [[Object]], false otherwise.
[[VisitedKeys]] | a List of Strings | The values that have been emitted by this iterator thus far.
[[RemainingKeys]] | a List of Strings | The values remaining to be emitted for the current object, before iterating the properties of its prototype (if its prototype is not null).

# 14.8 The `continue` Statement

## Syntax

ContinueStatement [Yield, Await] : continue ; continue [no LineTerminator here] LabelIdentifier [?Yield, ?Await] ;

# 14.8.1 Static Semantics: Early Errors

ContinueStatement : continue ; continue LabelIdentifier ;

- It is a Syntax Error if this ContinueStatement is not nested, directly or indirectly (but not crossing function or `static` initialization block boundaries), within an IterationStatement.

# 14.8.2 Runtime Semantics: Evaluation

ContinueStatement : continue ;

1. Return Completion Record { [[Type]]: continue, [[Value]]: empty, [[Target]]: empty }.

ContinueStatement : continue LabelIdentifier ;

1. Let label be the StringValue of LabelIdentifier.
2. Return Completion Record { [[Type]]: continue, [[Value]]: empty, [[Target]]: label }.

# 14.9 The `break` Statement

## Syntax

BreakStatement [Yield, Await] : break ; break [no LineTerminator here] LabelIdentifier [?Yield, ?Await] ;

# 14.9.1 Static Semantics: Early Errors

BreakStatement : break ;

- It is a Syntax Error if this BreakStatement is not nested, directly or indirectly (but not crossing function or `static` initialization block boundaries), within an IterationStatement or a SwitchStatement.

# 14.9.2 Runtime Semantics: Evaluation

BreakStatement : break ;

1. Return Completion Record { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.

BreakStatement : break LabelIdentifier ;

1. Let label be the StringValue of LabelIdentifier.
2. Return Completion Record { [[Type]]: break, [[Value]]: empty, [[Target]]: label }.

# 14.10 The `return` Statement

## Syntax

ReturnStatement [Yield, Await] : return ; return [no LineTerminator here] Expression [+In, ?Yield, ?Await] ; Note

A `return` statement causes a function to cease execution and, in most cases, returns a value to the caller. If Expression is omitted, the return value is undefined. Otherwise, the return value is the value of Expression. A `return` statement may not actually return a value to the caller depending on surrounding context. For example, in a `try` block, a `return` statement's Completion Record may be replaced with another Completion Record during evaluation of the `finally` block.

# 14.10.1 Runtime Semantics: Evaluation

ReturnStatement : return ;

1. Return ReturnCompletion(undefined).

ReturnStatement : return Expression ;

1. Let exprRef be ? Evaluation of Expression.
2. Let exprValue be ? GetValue(exprRef).
3. If GetGeneratorKind() is async, set exprValue to ? Await(exprValue).
4. Return ReturnCompletion(exprValue).

Legacy

# 14.11 The `with` Statement

Note 1

Use of the Legacy `with` statement is discouraged in new ECMAScript code. Consider alternatives that are permitted in both strict mode code and non-strict code, such as destructuring assignment.

## Syntax

WithStatement [Yield, Await, Return] : with ( Expression [+In, ?Yield, ?Await] ) Statement [?Yield, ?Await, ?Return] Note 2

The `with` statement adds an Object Environment Record for a computed object to the lexical environment of the running execution context. It then executes a statement using this augmented lexical environment. Finally, it restores the original lexical environment.

# 14.11.1 Static Semantics: Early Errors

WithStatement : with ( Expression ) Statement

- It is a Syntax Error if IsStrict(this production) is true.
- It is a Syntax Error if IsLabelledFunction(Statement) is true.

Note

It is only necessary to apply the second rule if the extension specified in B.3.1 is implemented.

# 14.11.2 Runtime Semantics: Evaluation

WithStatement : with ( Expression ) Statement

1. Let val be ? Evaluation of Expression.
2. Let obj be ? ToObject(? GetValue(val)).
3. Let oldEnv be the running execution context's LexicalEnvironment.
4. Let newEnv be NewObjectEnvironment(obj, true, oldEnv).
5. Set the running execution context's LexicalEnvironment to newEnv.
6. Let C be Completion(Evaluation of Statement).
7. Set the running execution context's LexicalEnvironment to oldEnv.
8. Return ? UpdateEmpty(C, undefined).

Note

No matter how control leaves the embedded Statement, whether normally or by some form of abrupt completion or exception, the LexicalEnvironment is always restored to its former state.

# 14.12 The `switch` Statement

## Syntax

SwitchStatement [Yield, Await, Return] : switch ( Expression [+In, ?Yield, ?Await] ) CaseBlock [?Yield, ?Await, ?Return] CaseBlock [Yield, Await, Return] : { CaseClauses [?Yield, ?Await, ?Return]opt } { CaseClauses [?Yield, ?Await, ?Return]opt DefaultClause [?Yield, ?Await, ?Return] CaseClauses [?Yield, ?Await, ?Return]opt } CaseClauses [Yield, Await, Return] : CaseClause [?Yield, ?Await, ?Return] CaseClauses [?Yield, ?Await, ?Return] CaseClause [?Yield, ?Await, ?Return] CaseClause [Yield, Await, Return] : case Expression [+In, ?Yield, ?Await] : StatementList [?Yield, ?Await, ?Return]opt DefaultClause [Yield, Await, Return] : default : StatementList [?Yield, ?Await, ?Return]opt

# 14.12.1 Static Semantics: Early Errors

SwitchStatement : switch ( Expression ) CaseBlock

- It is a Syntax Error if the LexicallyDeclaredNames of CaseBlock contains any duplicate entries, unless the host is a web browser or otherwise supports Block-Level Function Declarations Web Legacy Compatibility Semantics, and both of the following conditions are true:

  - IsStrict(this production) is false.
  - The duplicate entries are only bound by FunctionDeclarations.
- It is a Syntax Error if any element of the LexicallyDeclaredNames of CaseBlock also occurs in the VarDeclaredNames of CaseBlock.

# 14.12.2 Runtime Semantics: CaseBlockEvaluation

The syntax-directed operation CaseBlockEvaluation takes argument input (an ECMAScript language value) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

CaseBlock : { }

1. Return undefined.

CaseBlock : { CaseClauses }

1. Let V be undefined.
2. Let A be the List of CaseClause items in CaseClauses, in source text order.
3. Let found be false.
4. For each CaseClause C of A, do
   1. If found is false, then
      1. Set found to ? CaseClauseIsSelected(C, input).
   2. If found is true, then
      1. Let R be Completion(Evaluation of C).
      2. If R.[[Value]] is not empty, set V to R.[[Value]].
      3. If R is an abrupt completion, return ? UpdateEmpty(R, V).
5. Return V.

CaseBlock : { CaseClauses opt DefaultClause CaseClauses opt }

1. Let V be undefined.
2. If the first CaseClauses is present, then
   1. Let A be the List of CaseClause items in the first CaseClauses, in source text order.
3. Else,
   1. Let A be a new empty List.
4. Let found be false.
5. For each CaseClause C of A, do
   1. If found is false, then
      1. Set found to ? CaseClauseIsSelected(C, input).
   2. If found is true, then
      1. Let R be Completion(Evaluation of C).
      2. If R.[[Value]] is not empty, set V to R.[[Value]].
      3. If R is an abrupt completion, return ? UpdateEmpty(R, V).
6. Let foundInB be false.
7. If the second CaseClauses is present, then
   1. Let B be the List of CaseClause items in the second CaseClauses, in source text order.
8. Else,
   1. Let B be a new empty List.
9. If found is false, then
   1. For each CaseClause C of B, do
      1. If foundInB is false, then
         1. Set foundInB to ? CaseClauseIsSelected(C, input).
      2. If foundInB is true, then
         1. Let R be Completion(Evaluation of CaseClause C).
         2. If R.[[Value]] is not empty, set V to R.[[Value]].
         3. If R is an abrupt completion, return ? UpdateEmpty(R, V).
10. If foundInB is true, return V.
11. Let defaultR be Completion(Evaluation of DefaultClause).
12. If defaultR.[[Value]] is not empty, set V to defaultR.[[Value]].
13. If defaultR is an abrupt completion, return ? UpdateEmpty(defaultR, V).
14. NOTE: The following is another complete iteration of the second CaseClauses.
15. For each CaseClause C of B, do
    1. Let R be Completion(Evaluation of CaseClause C).
    2. If R.[[Value]] is not empty, set V to R.[[Value]].
    3. If R is an abrupt completion, return ? UpdateEmpty(R, V).
16. Return V.

# 14.12.3 CaseClauseIsSelected ( C, input )

The abstract operation CaseClauseIsSelected takes arguments C (a CaseClause Parse Node) and input (an ECMAScript language value) and returns either a normal completion containing a Boolean or an abrupt completion. It determines whether C matches input. It performs the following steps when called:

1. Assert: C is an instance of the production CaseClause : case Expression : StatementList opt .
2. Let exprRef be ? Evaluation of the Expression of C.
3. Let clauseSelector be ? GetValue(exprRef).
4. Return IsStrictlyEqual(input, clauseSelector).

Note

This operation does not execute C's StatementList (if any). The CaseBlock algorithm uses its return value to determine which StatementList to start executing.

# 14.12.4 Runtime Semantics: Evaluation

SwitchStatement : switch ( Expression ) CaseBlock

1. Let exprRef be ? Evaluation of Expression.
2. Let switchValue be ? GetValue(exprRef).
3. Let oldEnv be the running execution context's LexicalEnvironment.
4. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
5. Perform BlockDeclarationInstantiation(CaseBlock, blockEnv).
6. Set the running execution context's LexicalEnvironment to blockEnv.
7. Let R be Completion(CaseBlockEvaluation of CaseBlock with argument switchValue).
8. Set the running execution context's LexicalEnvironment to oldEnv.
9. Return R.

Note

No matter how control leaves the SwitchStatement the LexicalEnvironment is always restored to its former state.

CaseClause : case Expression :

1. Return empty.

CaseClause : case Expression : StatementList

1. Return ? Evaluation of StatementList.

DefaultClause : default :

1. Return empty.

DefaultClause : default : StatementList

1. Return ? Evaluation of StatementList.

# 14.13 Labelled Statements

## Syntax

LabelledStatement [Yield, Await, Return] : LabelIdentifier [?Yield, ?Await] : LabelledItem [?Yield, ?Await, ?Return] LabelledItem [Yield, Await, Return] : Statement [?Yield, ?Await, ?Return] FunctionDeclaration [?Yield, ?Await, ~Default] Note

A Statement may be prefixed by a label. Labelled statements are only used in conjunction with labelled `break` and `continue` statements. ECMAScript has no `goto` statement. A Statement can be part of a LabelledStatement, which itself can be part of a LabelledStatement, and so on. The labels introduced this way are collectively referred to as the “current label set” when describing the semantics of individual statements.

# 14.13.1 Static Semantics: Early Errors

LabelledItem : FunctionDeclaration

- It is a Syntax Error if any source text is matched by this production, unless that source text is non-strict code and the host is a web browser or otherwise supports Labelled Function Declarations.

# 14.13.2 Static Semantics: IsLabelledFunction ( stmt )

The abstract operation IsLabelledFunction takes argument stmt (a Statement Parse Node) and returns a Boolean. It performs the following steps when called:

1. If stmt is not a LabelledStatement, return false.
2. Let item be the LabelledItem of stmt.
3. If item is LabelledItem : FunctionDeclaration , return true.
4. Let subStmt be the Statement of item.
5. Return IsLabelledFunction(subStmt).

# 14.13.3 Runtime Semantics: Evaluation

LabelledStatement : LabelIdentifier : LabelledItem

1. Return ? LabelledEvaluation of this LabelledStatement with argument « ».

# 14.13.4 Runtime Semantics: LabelledEvaluation

The syntax-directed operation LabelledEvaluation takes argument labelSet (a List of Strings) and returns either a normal completion containing either an ECMAScript language value or empty, or an abrupt completion. It is defined piecewise over the following productions:

BreakableStatement : IterationStatement

1. Let stmtResult be Completion(LoopEvaluation of IterationStatement with argument labelSet).
2. If stmtResult is a break completion, then
   1. If stmtResult.[[Target]] is empty, then
      1. If stmtResult.[[Value]] is empty, set stmtResult to NormalCompletion(undefined).
      2. Else, set stmtResult to NormalCompletion(stmtResult.[[Value]]).
3. Return ? stmtResult.

BreakableStatement : SwitchStatement

1. Let stmtResult be Completion(Evaluation of SwitchStatement).
2. If stmtResult is a break completion, then
   1. If stmtResult.[[Target]] is empty, then
      1. If stmtResult.[[Value]] is empty, set stmtResult to NormalCompletion(undefined).
      2. Else, set stmtResult to NormalCompletion(stmtResult.[[Value]]).
3. Return ? stmtResult.

Note 1

A BreakableStatement is one that can be exited via an unlabelled BreakStatement.

LabelledStatement : LabelIdentifier : LabelledItem

1. Let label be the StringValue of LabelIdentifier.
2. Let newLabelSet be the list-concatenation of labelSet and « label ».
3. Let stmtResult be Completion(LabelledEvaluation of LabelledItem with argument newLabelSet).
4. If stmtResult is a break completion and stmtResult.[[Target]] is label, then
   1. Set stmtResult to NormalCompletion(stmtResult.[[Value]]).
5. Return ? stmtResult.

LabelledItem : FunctionDeclaration

1. Return ? Evaluation of FunctionDeclaration.

Statement : BlockStatement VariableStatement EmptyStatement ExpressionStatement IfStatement ContinueStatement BreakStatement ReturnStatement WithStatement ThrowStatement TryStatement DebuggerStatement

1. Return ? Evaluation of Statement.

Note 2

The only two productions of Statement which have special semantics for LabelledEvaluation are BreakableStatement and LabelledStatement.

# 14.14 The `throw` Statement

## Syntax

ThrowStatement [Yield, Await] : throw [no LineTerminator here] Expression [+In, ?Yield, ?Await] ;

# 14.14.1 Runtime Semantics: Evaluation

ThrowStatement : throw Expression ;

1. Let exprRef be ? Evaluation of Expression.
2. Let exprValue be ? GetValue(exprRef).
3. Return ThrowCompletion(exprValue).

# 14.15 The `try` Statement

## Syntax

TryStatement [Yield, Await, Return] : try Block [?Yield, ?Await, ?Return] Catch [?Yield, ?Await, ?Return] try Block [?Yield, ?Await, ?Return] Finally [?Yield, ?Await, ?Return] try Block [?Yield, ?Await, ?Return] Catch [?Yield, ?Await, ?Return] Finally [?Yield, ?Await, ?Return] Catch [Yield, Await, Return] : catch ( CatchParameter [?Yield, ?Await] ) Block [?Yield, ?Await, ?Return] catch Block [?Yield, ?Await, ?Return] Finally [Yield, Await, Return] : finally Block [?Yield, ?Await, ?Return] CatchParameter [Yield, Await] : BindingIdentifier [?Yield, ?Await] BindingPattern [?Yield, ?Await] Note

The `try` statement encloses a block of code in which an exceptional condition can occur, such as a runtime error or a `throw` statement. The `catch` clause provides the exception-handling code. When a catch clause catches an exception, its CatchParameter is bound to that exception.

# 14.15.1 Static Semantics: Early Errors

Catch : catch ( CatchParameter ) Block

- It is a Syntax Error if the BoundNames of CatchParameter contains any duplicate elements.
- It is a Syntax Error if any element of the BoundNames of CatchParameter also occurs in the LexicallyDeclaredNames of Block.
- It is a Syntax Error if any element of the BoundNames of CatchParameter also occurs in the VarDeclaredNames of Block , unless CatchParameter is CatchParameter : BindingIdentifier and the host is a web browser or otherwise supports VariableStatements in Catch Blocks.

# 14.15.2 Runtime Semantics: CatchClauseEvaluation

The syntax-directed operation CatchClauseEvaluation takes argument thrownValue (an ECMAScript language value) and returns either a normal completion containing either an ECMAScript language value or empty, or an abrupt completion. It is defined piecewise over the following productions:

Catch : catch ( CatchParameter ) Block

1. Let oldEnv be the running execution context's LexicalEnvironment.
2. Let catchEnv be NewDeclarativeEnvironment(oldEnv).
3. For each element argName of the BoundNames of CatchParameter, do
   1. Perform ! catchEnv.CreateMutableBinding(argName, false).
4. Set the running execution context's LexicalEnvironment to catchEnv.
5. Let status be Completion(BindingInitialization of CatchParameter with arguments thrownValue and catchEnv).
6. If status is an abrupt completion, then
   1. Set the running execution context's LexicalEnvironment to oldEnv.
   2. Return ? status.
7. Let B be Completion(Evaluation of Block).
8. Set the running execution context's LexicalEnvironment to oldEnv.
9. Return ? B.

Catch : catch Block

1. Return ? Evaluation of Block.

Note

No matter how control leaves the Block the LexicalEnvironment is always restored to its former state.

# 14.15.3 Runtime Semantics: Evaluation

TryStatement : try Block Catch

1. Let B be Completion(Evaluation of Block).
2. If B is a throw completion, let C be Completion(CatchClauseEvaluation of Catch with argument B.[[Value]]).
3. Else, let C be B.
4. Return ? UpdateEmpty(C, undefined).

TryStatement : try Block Finally

1. Let B be Completion(Evaluation of Block).
2. Let F be Completion(Evaluation of Finally).
3. If F is a normal completion, set F to B.
4. Return ? UpdateEmpty(F, undefined).

TryStatement : try Block Catch Finally

1. Let B be Completion(Evaluation of Block).
2. If B is a throw completion, let C be Completion(CatchClauseEvaluation of Catch with argument B.[[Value]]).
3. Else, let C be B.
4. Let F be Completion(Evaluation of Finally).
5. If F is a normal completion, set F to C.
6. Return ? UpdateEmpty(F, undefined).

# 14.16 The `debugger` Statement

## Syntax

DebuggerStatement : debugger ;

# 14.16.1 Runtime Semantics: Evaluation

Note

Evaluating a DebuggerStatement may allow an implementation to cause a breakpoint when run under a debugger. If a debugger is not present or active this statement has no observable effect.

DebuggerStatement : debugger ;

1. If an implementation-defined debugging facility is available and enabled, then
   1. Perform an implementation-defined debugging action.
   2. Return a new implementation-defined Completion Record.
2. Return empty.