Multipage preference

Stage 1 Draft / July 8, 2026

Declarations in Conditionals

Introduction

This is the formal specification for a proposed extension of the if and while JavaScript control flow statements. It modifies the original ECMAScript specification with several new or revised clauses. See the proposal's explainer for the proposal's background, motivation, and usage examples.

This proposal is specified against ECMAScript as extended by the Explicit Resource Management proposal.

14 ECMAScript Language: Statements and Declarations

14.6 The if Statement

Syntax

IfStatement[Yield, Await, Return] : if ( Expression[+In, ?Yield, ?Await] IfCondition[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] else Statement[?Yield, ?Await, ?Return] if ( Expression[+In, ?Yield, ?Await] IfCondition[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] [lookahead ≠ else] IfCondition[In, Yield, Await] : Expression[?In, ?Yield, ?Await] LetOrConst BindingIdentifier[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] using [no LineTerminator here] BindingIdentifier[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] CoverAwaitExpressionAndAwaitUsingDeclarationHead[?Yield] [no LineTerminator here] BindingIdentifier[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] LexicalDeclaration[?In, ?Yield, ?Await] ; Expression[?In, ?Yield, ?Await] 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 ifs

14.6.1 Static Semantics: Early Errors

IfStatement : if ( Expression IfCondition ) Statement else Statement IfStatement : if ( Expression IfCondition ) Statement Note 1

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

Note 2

The BoundNames of an IfCondition are scoped to the first Statement, so a var of the same name in second Statement would refer to a different variable. Disallowing this avoids the resulting ambiguity. The second Statement (the else branch, if it exists) is unaffected by these names and may freely contain a var of the same name.

14.6.2 Static Semantics: BoundNames

IfCondition : Expression
  1. Return a new empty List.
IfCondition : LetOrConst BindingIdentifier Initializer using BindingIdentifier Initializer CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer
  1. Return the BoundNames of BindingIdentifier.
IfCondition : LexicalDeclaration ; Expression
  1. Return the BoundNames of LexicalDeclaration.

14.6.3 Static Semantics: IsConstantDeclaration

IfCondition : Expression
  1. Return false.
IfCondition : LetOrConst BindingIdentifier Initializer
  1. Return IsConstantDeclaration of LetOrConst.
IfCondition : using BindingIdentifier Initializer CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer
  1. Return true.
IfCondition : LexicalDeclaration ; Expression
  1. Return IsConstantDeclaration of LexicalDeclaration.

14.6.4 Runtime Semantics: IfConditionDeclarationInstantiation

The syntax-directed operation IfConditionDeclarationInstantiation takes argument env (a Declarative Environment Record) and returns unused. It creates the bindings declared by IfCondition in env. It is defined piecewise over the following productions:

IfCondition : Expression
  1. Return unused.
IfCondition : LetOrConst BindingIdentifier Initializer using BindingIdentifier Initializer CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer LexicalDeclaration ; Expression
  1. Let isConst be IsConstantDeclaration of IfCondition.
  2. For each element dn of the BoundNames of IfCondition, do
    1. If isConst is true, then
      1. Perform ! env.CreateImmutableBinding(dn, true).
    2. Else,
      1. Perform ! env.CreateMutableBinding(dn, false).
  3. Return unused.

14.6.5 Runtime Semantics: Evaluation

IfStatement : if ( Expression IfCondition ) Statement else Statement
  1. Let oldEnv be the running execution context's LexicalEnvironment.
  2. If the BoundNames of IfCondition is not empty, then
    1. Let ifEnv be NewDeclarativeEnvironment(oldEnv).
    2. Perform IfConditionDeclarationInstantiation of IfCondition with argument ifEnv.
    3. Set the running execution context's LexicalEnvironment to ifEnv.
  3. Else,
    1. Let ifEnv be oldEnv.
  4. Let exprRef be Completion(Evaluation of ExpressionIfCondition).
  5. If exprRef is a normal completion, set exprRef to Completion(GetValue(exprRef.[[Value]])).
  6. If exprRef is an abrupt completion, then
    1. If ifEnv is not oldEnv, then
      1. Set exprRef to Completion(DisposeResources(ifEnv.[[DisposeCapability]], exprRef)).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
    2. Return ? exprRef.
  7. Let exprValue be ToBoolean(GetValue(exprRef)exprRef.[[Value]]).
  8. If exprValue is true, then
    1. Let stmtCompletion be Completion(Evaluation of the first Statement).
    2. If ifEnv is not oldEnv, then
      1. Set stmtCompletion to Completion(DisposeResources(ifEnv.[[DisposeCapability]], stmtCompletion)).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
  9. Else,
    1. If ifEnv is not oldEnv, then
      1. Let disposeCompletion be Completion(DisposeResources(ifEnv.[[DisposeCapability]], NormalCompletion(undefined))).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
      3. If disposeCompletion is an abrupt completion, return ? disposeCompletion.
    2. Let stmtCompletion be Completion(Evaluation of the second Statement).
  10. Return ? UpdateEmpty(stmtCompletion, undefined).
IfStatement : if ( Expression IfCondition ) Statement
  1. Let oldEnv be the running execution context's LexicalEnvironment.
  2. If the BoundNames of IfCondition is not empty, then
    1. Let ifEnv be NewDeclarativeEnvironment(oldEnv).
    2. Perform IfConditionDeclarationInstantiation of IfCondition with argument ifEnv.
    3. Set the running execution context's LexicalEnvironment to ifEnv.
  3. Else,
    1. Let ifEnv be oldEnv.
  4. Let exprRef be Completion(Evaluation of ExpressionIfCondition).
  5. If exprRef is a normal completion, set exprRef to Completion(GetValue(exprRef.[[Value]])).
  6. If exprRef is an abrupt completion, then
    1. If ifEnv is not oldEnv, then
      1. Set exprRef to Completion(DisposeResources(ifEnv.[[DisposeCapability]], exprRef)).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
    2. Return ? exprRef.
  7. Let exprValue be ToBoolean(GetValue(exprRef)exprRef.[[Value]]).
  8. If exprValue is false, then
    1. If ifEnv is not oldEnv, then
      1. Perform ? DisposeResources(ifEnv.[[DisposeCapability]], NormalCompletion(undefined)).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
    2. Return undefined.
  9. Else,
    1. Let stmtCompletion be Completion(Evaluation of Statement).
    2. If ifEnv is not oldEnv, then
      1. Set stmtCompletion to Completion(DisposeResources(ifEnv.[[DisposeCapability]], stmtCompletion)).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
    3. Return ? UpdateEmpty(stmtCompletion, undefined).
IfCondition : Expression
  1. Return ? Evaluation of Expression.
IfCondition : LetOrConst 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 value.
IfCondition : using BindingIdentifier Initializer
  1. Let bindingId be the StringValue of BindingIdentifier.
  2. Let lhs be ! ResolveBinding(bindingId).
  3. Let rhs be ? Evaluation of Initializer.
  4. Let value be ? GetValue(rhs).
  5. Assert: IsUnresolvableReference(lhs) is false.
  6. Let base be lhs.[[Base]].
  7. Assert: base is a Declarative Environment Record.
  8. Perform ? AddDisposableResource(base.[[DisposableResourceStack]], value, sync-dispose).
  9. Perform ! InitializeReferencedBinding(lhs, value).
  10. Return value.
IfCondition : CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer
  1. Let bindingId be the StringValue of BindingIdentifier.
  2. Let lhs be ! ResolveBinding(bindingId).
  3. Let rhs be ? Evaluation of Initializer.
  4. Let value be ? GetValue(rhs).
  5. Assert: IsUnresolvableReference(lhs) is false.
  6. Let base be lhs.[[Base]].
  7. Assert: base is a Declarative Environment Record.
  8. Perform ? AddDisposableResource(base.[[DisposableResourceStack]], value, async-dispose).
  9. Perform ! InitializeReferencedBinding(lhs, value).
  10. Return value.
IfCondition : LexicalDeclaration ; Expression
  1. Perform ? Evaluation of LexicalDeclaration.
  2. Return ? Evaluation of Expression.

14.7 Iteration Statements

14.7.3 The while Statement

Syntax

WhileStatement[Yield, Await, Return] : while ( Expression[+In, ?Yield, ?Await] WhileCondition[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] WhileCondition[In, Yield, Await] : Expression[?In, ?Yield, ?Await] LetOrConst BindingIdentifier[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] using [no LineTerminator here] BindingIdentifier[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] CoverAwaitExpressionAndAwaitUsingDeclarationHead[?Yield] [no LineTerminator here] BindingIdentifier[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] LexicalDeclaration[?In, ?Yield, ?Await] ; Expression[?In, ?Yield, ?Await]

14.7.3.1 Static Semantics: Early Errors

WhileStatement : while ( Expression WhileCondition ) Statement Note 1

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

Note 2

The BoundNames of a WhileCondition are scoped to the Statement, so a var of the same name in the Statement would refer to a different variable. Disallowing this avoids the resulting ambiguity.

14.7.3.2 Static Semantics: BoundNames

WhileCondition : Expression
  1. Return a new empty List.
WhileCondition : LetOrConst BindingIdentifier Initializer using BindingIdentifier Initializer CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer
  1. Return the BoundNames of BindingIdentifier.
WhileCondition : LexicalDeclaration ; Expression
  1. Return the BoundNames of LexicalDeclaration.

14.7.3.3 Static Semantics: IsConstantDeclaration

WhileCondition : Expression
  1. Return false.
WhileCondition : LetOrConst BindingIdentifier Initializer
  1. Return IsConstantDeclaration of LetOrConst.
WhileCondition : using BindingIdentifier Initializer CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer
  1. Return true.
WhileCondition : LexicalDeclaration ; Expression
  1. Return IsConstantDeclaration of LexicalDeclaration.

14.7.3.4 Runtime Semantics: WhileConditionDeclarationInstantiation

The syntax-directed operation WhileConditionDeclarationInstantiation takes argument env (a Declarative Environment Record) and returns unused. It creates the bindings declared by WhileCondition in env. It is defined piecewise over the following productions:

WhileCondition : Expression
  1. Return unused.
WhileCondition : LetOrConst BindingIdentifier Initializer using BindingIdentifier Initializer CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer LexicalDeclaration ; Expression
  1. Let isConst be IsConstantDeclaration of WhileCondition.
  2. For each element dn of the BoundNames of WhileCondition, do
    1. If isConst is true, then
      1. Perform ! env.CreateImmutableBinding(dn, true).
    2. Else,
      1. Perform ! env.CreateMutableBinding(dn, false).
  3. Return unused.

14.7.3.5 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 WhileCondition ) Statement
  1. Let V be undefined.
  2. Let oldEnv be the running execution context's LexicalEnvironment.
  3. Let hasDeclarations be false.
  4. If the BoundNames of WhileCondition is not empty, set hasDeclarations to true.
  5. Repeat,
    1. If hasDeclarations is true, then
      1. Let whileEnv be NewDeclarativeEnvironment(oldEnv).
      2. Perform WhileConditionDeclarationInstantiation of WhileCondition with argument whileEnv.
      3. Set the running execution context's LexicalEnvironment to whileEnv.
    2. Else,
      1. Let whileEnv be oldEnv.
    3. Let exprRef be Completion(Evaluation of ExpressionWhileCondition).
    4. If exprRef is a normal completion, set exprRef to Completion(GetValue(exprRef.[[Value]])).
    5. Let exprValue be ? GetValue(exprRef).
    6. If exprRef is an abrupt completion, then
      1. If whileEnv is not oldEnv, then
        1. Set exprRef to Completion(DisposeResources(whileEnv.[[DisposeCapability]], exprRef)).
        2. Set the running execution context's LexicalEnvironment to oldEnv.
      2. Return ? exprRef.
    7. If ToBoolean(exprValue) is false, return VToBoolean(exprRef.[[Value]]) is false, then
      1. If whileEnv is not oldEnv, then
        1. Perform ? DisposeResources(whileEnv.[[DisposeCapability]], NormalCompletion(undefined)).
        2. Set the running execution context's LexicalEnvironment to oldEnv.
      2. Return V.
    8. Let stmtResult be Completion(Evaluation of Statement).
    9. If whileEnv is not oldEnv, then
      1. Set stmtResult to Completion(DisposeResources(whileEnv.[[DisposeCapability]], stmtResult)).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
    10. If LoopContinues(stmtResult, labelSet) is false, return ? UpdateEmpty(stmtResult, V).
    11. If stmtResult.[[Value]] is not empty, set V to stmtResult.[[Value]].
WhileCondition : Expression
  1. Return ? Evaluation of Expression.
WhileCondition : LetOrConst 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 value.
WhileCondition : using BindingIdentifier Initializer
  1. Let bindingId be the StringValue of BindingIdentifier.
  2. Let lhs be ! ResolveBinding(bindingId).
  3. Let rhs be ? Evaluation of Initializer.
  4. Let value be ? GetValue(rhs).
  5. Assert: IsUnresolvableReference(lhs) is false.
  6. Let base be lhs.[[Base]].
  7. Assert: base is a Declarative Environment Record.
  8. Perform ? AddDisposableResource(base.[[DisposableResourceStack]], value, sync-dispose).
  9. Perform ! InitializeReferencedBinding(lhs, value).
  10. Return value.
WhileCondition : CoverAwaitExpressionAndAwaitUsingDeclarationHead BindingIdentifier Initializer
  1. Let bindingId be the StringValue of BindingIdentifier.
  2. Let lhs be ! ResolveBinding(bindingId).
  3. Let rhs be ? Evaluation of Initializer.
  4. Let value be ? GetValue(rhs).
  5. Assert: IsUnresolvableReference(lhs) is false.
  6. Let base be lhs.[[Base]].
  7. Assert: base is a Declarative Environment Record.
  8. Perform ? AddDisposableResource(base.[[DisposableResourceStack]], value, async-dispose).
  9. Perform ! InitializeReferencedBinding(lhs, value).
  10. Return value.
WhileCondition : LexicalDeclaration ; Expression
  1. Perform ? Evaluation of LexicalDeclaration.
  2. Return ? Evaluation of Expression.

Copyright & Software License

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.