ECMAScript® 2024 Language Specification

Draft ECMA-262 / December 6, 2023

13.15 Assignment Operators

Syntax

AssignmentExpression[In, Yield, Await] : ConditionalExpression[?In, ?Yield, ?Await] [+Yield] YieldExpression[?In, ?Await] ArrowFunction[?In, ?Yield, ?Await] AsyncArrowFunction[?In, ?Yield, ?Await] LeftHandSideExpression[?Yield, ?Await] = AssignmentExpression[?In, ?Yield, ?Await] LeftHandSideExpression[?Yield, ?Await] AssignmentOperator AssignmentExpression[?In, ?Yield, ?Await] LeftHandSideExpression[?Yield, ?Await] &&= AssignmentExpression[?In, ?Yield, ?Await] LeftHandSideExpression[?Yield, ?Await] ||= AssignmentExpression[?In, ?Yield, ?Await] LeftHandSideExpression[?Yield, ?Await] ??= AssignmentExpression[?In, ?Yield, ?Await] AssignmentOperator : one of *= /= %= += -= <<= >>= >>>= &= ^= |= **=

13.15.1 Static Semantics: Early Errors

AssignmentExpression : LeftHandSideExpression = AssignmentExpression

If LeftHandSideExpression is either an ObjectLiteral or an ArrayLiteral, the following Early Error rules are applied:

If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, the following Early Error rule is applied:

AssignmentExpression : LeftHandSideExpression AssignmentOperator AssignmentExpression LeftHandSideExpression &&= AssignmentExpression LeftHandSideExpression ||= AssignmentExpression LeftHandSideExpression ??= AssignmentExpression

13.15.2 Runtime Semantics: Evaluation

AssignmentExpression : LeftHandSideExpression = AssignmentExpression
  1. If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, then
    1. Let lref be ? Evaluation of LeftHandSideExpression.
    2. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
      1. Let rval be ? NamedEvaluation of AssignmentExpression with argument lref.[[ReferencedName]].
    3. Else,
      1. Let rref be ? Evaluation of AssignmentExpression.
      2. Let rval be ? GetValue(rref).
    4. Perform ? PutValue(lref, rval).
    5. Return rval.
  2. Let assignmentPattern be the AssignmentPattern that is covered by LeftHandSideExpression.
  3. Let rref be ? Evaluation of AssignmentExpression.
  4. Let rval be ? GetValue(rref).
  5. Perform ? DestructuringAssignmentEvaluation of assignmentPattern with argument rval.
  6. Return rval.
AssignmentExpression : LeftHandSideExpression AssignmentOperator AssignmentExpression
  1. Let lref be ? Evaluation of LeftHandSideExpression.
  2. Let lval be ? GetValue(lref).
  3. Let rref be ? Evaluation of AssignmentExpression.
  4. Let rval be ? GetValue(rref).
  5. Let assignmentOpText be the source text matched by AssignmentOperator.
  6. Let opText be the sequence of Unicode code points associated with assignmentOpText in the following table:
    assignmentOpText opText
    **= **
    *= *
    /= /
    %= %
    += +
    -= -
    <<= <<
    >>= >>
    >>>= >>>
    &= &
    ^= ^
    |= |
  7. Let r be ? ApplyStringOrNumericBinaryOperator(lval, opText, rval).
  8. Perform ? PutValue(lref, r).
  9. Return r.
AssignmentExpression : LeftHandSideExpression &&= AssignmentExpression
  1. Let lref be ? Evaluation of LeftHandSideExpression.
  2. Let lval be ? GetValue(lref).
  3. Let lbool be ToBoolean(lval).
  4. If lbool is false, return lval.
  5. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and IsIdentifierRef of LeftHandSideExpression is true, then
    1. Let rval be ? NamedEvaluation of AssignmentExpression with argument lref.[[ReferencedName]].
  6. Else,
    1. Let rref be ? Evaluation of AssignmentExpression.
    2. Let rval be ? GetValue(rref).
  7. Perform ? PutValue(lref, rval).
  8. Return rval.
AssignmentExpression : LeftHandSideExpression ||= AssignmentExpression
  1. Let lref be ? Evaluation of LeftHandSideExpression.
  2. Let lval be ? GetValue(lref).
  3. Let lbool be ToBoolean(lval).
  4. If lbool is true, return lval.
  5. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and IsIdentifierRef of LeftHandSideExpression is true, then
    1. Let rval be ? NamedEvaluation of AssignmentExpression with argument lref.[[ReferencedName]].
  6. Else,
    1. Let rref be ? Evaluation of AssignmentExpression.
    2. Let rval be ? GetValue(rref).
  7. Perform ? PutValue(lref, rval).
  8. Return rval.
AssignmentExpression : LeftHandSideExpression ??= AssignmentExpression
  1. Let lref be ? Evaluation of LeftHandSideExpression.
  2. Let lval be ? GetValue(lref).
  3. If lval is neither undefined nor null, return lval.
  4. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and IsIdentifierRef of LeftHandSideExpression is true, then
    1. Let rval be ? NamedEvaluation of AssignmentExpression with argument lref.[[ReferencedName]].
  5. Else,
    1. Let rref be ? Evaluation of AssignmentExpression.
    2. Let rval be ? GetValue(rref).
  6. Perform ? PutValue(lref, rval).
  7. Return rval.
Note

When this expression occurs within strict mode code, it is a runtime error if lref in step 1.d, 2, 2, 2, 2 is an unresolvable reference. If it is, a ReferenceError exception is thrown. Additionally, it is a runtime error if the lref in step 8, 7, 7, 6 is a reference to a data property with the attribute value { [[Writable]]: false }, to an accessor property with the attribute value { [[Set]]: undefined }, or to a non-existent property of an object for which the IsExtensible predicate returns the value false. In these cases a TypeError exception is thrown.

13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval )

The abstract operation ApplyStringOrNumericBinaryOperator takes arguments lval (an ECMAScript language value), opText (**, *, /, %, +, -, <<, >>, >>>, &, ^, or |), and rval (an ECMAScript language value) and returns either a normal completion containing either a String, a BigInt, or a Number, or a throw completion. It performs the following steps when called:

  1. If opText is +, then
    1. Let lprim be ? ToPrimitive(lval).
    2. Let rprim be ? ToPrimitive(rval).
    3. If lprim is a String or rprim is a String, then
      1. Let lstr be ? ToString(lprim).
      2. Let rstr be ? ToString(rprim).
      3. Return the string-concatenation of lstr and rstr.
    4. Set lval to lprim.
    5. Set rval to rprim.
  2. NOTE: At this point, it must be a numeric operation.
  3. Let lnum be ? ToNumeric(lval).
  4. Let rnum be ? ToNumeric(rval).
  5. If Type(lnum) is not Type(rnum), throw a TypeError exception.
  6. If lnum is a BigInt, then
    1. If opText is **, return ? BigInt::exponentiate(lnum, rnum).
    2. If opText is /, return ? BigInt::divide(lnum, rnum).
    3. If opText is %, return ? BigInt::remainder(lnum, rnum).
    4. If opText is >>>, return ? BigInt::unsignedRightShift(lnum, rnum).
  7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table:
    opText Type(lnum) operation
    ** Number Number::exponentiate
    * Number Number::multiply
    * BigInt BigInt::multiply
    / Number Number::divide
    % Number Number::remainder
    + Number Number::add
    + BigInt BigInt::add
    - Number Number::subtract
    - BigInt BigInt::subtract
    << Number Number::leftShift
    << BigInt BigInt::leftShift
    >> Number Number::signedRightShift
    >> BigInt BigInt::signedRightShift
    >>> Number Number::unsignedRightShift
    & Number Number::bitwiseAND
    & BigInt BigInt::bitwiseAND
    ^ Number Number::bitwiseXOR
    ^ BigInt BigInt::bitwiseXOR
    | Number Number::bitwiseOR
    | BigInt BigInt::bitwiseOR
  8. Return operation(lnum, rnum).
Note 1

No hint is provided in the calls to ToPrimitive in steps 1.a and 1.b. All standard objects except Dates handle the absence of a hint as if number were given; Dates handle the absence of a hint as if string were given. Exotic objects may handle the absence of a hint in some other manner.

Note 2

Step 1.c differs from step 3 of the IsLessThan algorithm, by using the logical-or operation instead of the logical-and operation.

13.15.4 EvaluateStringOrNumericBinaryExpression ( leftOperand, opText, rightOperand )

The abstract operation EvaluateStringOrNumericBinaryExpression takes arguments leftOperand (a Parse Node), opText (a sequence of Unicode code points), and rightOperand (a Parse Node) and returns either a normal completion containing either a String, a BigInt, or a Number, or an abrupt completion. It performs the following steps when called:

  1. Let lref be ? Evaluation of leftOperand.
  2. Let lval be ? GetValue(lref).
  3. Let rref be ? Evaluation of rightOperand.
  4. Let rval be ? GetValue(rref).
  5. Return ? ApplyStringOrNumericBinaryOperator(lval, opText, rval).

13.15.5 Destructuring Assignment

Supplemental Syntax

In certain circumstances when processing an instance of the production
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
the interpretation of LeftHandSideExpression is refined using the following grammar:

AssignmentPattern[Yield, Await] : ObjectAssignmentPattern[?Yield, ?Await] ArrayAssignmentPattern[?Yield, ?Await] ObjectAssignmentPattern[Yield, Await] : { } { AssignmentRestProperty[?Yield, ?Await] } { AssignmentPropertyList[?Yield, ?Await] } { AssignmentPropertyList[?Yield, ?Await] , AssignmentRestProperty[?Yield, ?Await]opt } ArrayAssignmentPattern[Yield, Await] : [ Elisionopt AssignmentRestElement[?Yield, ?Await]opt ] [ AssignmentElementList[?Yield, ?Await] ] [ AssignmentElementList[?Yield, ?Await] , Elisionopt AssignmentRestElement[?Yield, ?Await]opt ] AssignmentRestProperty[Yield, Await] : ... DestructuringAssignmentTarget[?Yield, ?Await] AssignmentPropertyList[Yield, Await] : AssignmentProperty[?Yield, ?Await] AssignmentPropertyList[?Yield, ?Await] , AssignmentProperty[?Yield, ?Await] AssignmentElementList[Yield, Await] : AssignmentElisionElement[?Yield, ?Await] AssignmentElementList[?Yield, ?Await] , AssignmentElisionElement[?Yield, ?Await] AssignmentElisionElement[Yield, Await] : Elisionopt AssignmentElement[?Yield, ?Await] AssignmentProperty[Yield, Await] : IdentifierReference[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]opt PropertyName[?Yield, ?Await] : AssignmentElement[?Yield, ?Await] AssignmentElement[Yield, Await] : DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]opt AssignmentRestElement[Yield, Await] : ... DestructuringAssignmentTarget[?Yield, ?Await] DestructuringAssignmentTarget[Yield, Await] : LeftHandSideExpression[?Yield, ?Await]

13.15.5.1 Static Semantics: Early Errors

AssignmentProperty : IdentifierReference Initializeropt AssignmentRestProperty : ... DestructuringAssignmentTarget DestructuringAssignmentTarget : LeftHandSideExpression

If LeftHandSideExpression is either an ObjectLiteral or an ArrayLiteral, the following Early Error rules are applied:

If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, the following Early Error rule is applied:

13.15.5.2 Runtime Semantics: DestructuringAssignmentEvaluation

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

ObjectAssignmentPattern : { }
  1. Perform ? RequireObjectCoercible(value).
  2. Return unused.
ObjectAssignmentPattern : { AssignmentPropertyList } { AssignmentPropertyList , }
  1. Perform ? RequireObjectCoercible(value).
  2. Perform ? PropertyDestructuringAssignmentEvaluation of AssignmentPropertyList with argument value.
  3. Return unused.
ObjectAssignmentPattern : { AssignmentRestProperty }
  1. Perform ? RequireObjectCoercible(value).
  2. Let excludedNames be a new empty List.
  3. Return ? RestDestructuringAssignmentEvaluation of AssignmentRestProperty with arguments value and excludedNames.
ObjectAssignmentPattern : { AssignmentPropertyList , AssignmentRestProperty }
  1. Perform ? RequireObjectCoercible(value).
  2. Let excludedNames be ? PropertyDestructuringAssignmentEvaluation of AssignmentPropertyList with argument value.
  3. Return ? RestDestructuringAssignmentEvaluation of AssignmentRestProperty with arguments value and excludedNames.
ArrayAssignmentPattern : [ ]
  1. Let iteratorRecord be ? GetIterator(value, sync).
  2. Return ? IteratorClose(iteratorRecord, NormalCompletion(unused)).
ArrayAssignmentPattern : [ Elision ]
  1. Let iteratorRecord be ? GetIterator(value, sync).
  2. Let result be Completion(IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord).
  3. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, result).
  4. Return result.
ArrayAssignmentPattern : [ Elisionopt AssignmentRestElement ]
  1. Let iteratorRecord be ? GetIterator(value, sync).
  2. If Elision is present, then
    1. Let status be Completion(IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord).
    2. If status is an abrupt completion, then
      1. Assert: iteratorRecord.[[Done]] is true.
      2. Return ? status.
  3. Let result be Completion(IteratorDestructuringAssignmentEvaluation of AssignmentRestElement with argument iteratorRecord).
  4. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, result).
  5. Return result.
ArrayAssignmentPattern : [ AssignmentElementList ]
  1. Let iteratorRecord be ? GetIterator(value, sync).
  2. Let result be Completion(IteratorDestructuringAssignmentEvaluation of AssignmentElementList with argument iteratorRecord).
  3. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, result).
  4. Return result.
ArrayAssignmentPattern : [ AssignmentElementList , Elisionopt AssignmentRestElementopt ]
  1. Let iteratorRecord be ? GetIterator(value, sync).
  2. Let status be Completion(IteratorDestructuringAssignmentEvaluation of AssignmentElementList with argument iteratorRecord).
  3. If status is an abrupt completion, then
    1. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, status).
    2. Return ? status.
  4. If Elision is present, then
    1. Set status to Completion(IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord).
    2. If status is an abrupt completion, then
      1. Assert: iteratorRecord.[[Done]] is true.
      2. Return ? status.
  5. If AssignmentRestElement is present, then
    1. Set status to Completion(IteratorDestructuringAssignmentEvaluation of AssignmentRestElement with argument iteratorRecord).
  6. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, status).
  7. Return ? status.

13.15.5.3 Runtime Semantics: PropertyDestructuringAssignmentEvaluation

The syntax-directed operation PropertyDestructuringAssignmentEvaluation takes argument value (an ECMAScript language value) and returns either a normal completion containing a List of property keys or an abrupt completion. It collects a list of all destructured property keys. It is defined piecewise over the following productions:

AssignmentPropertyList : AssignmentPropertyList , AssignmentProperty
  1. Let propertyNames be ? PropertyDestructuringAssignmentEvaluation of AssignmentPropertyList with argument value.
  2. Let nextNames be ? PropertyDestructuringAssignmentEvaluation of AssignmentProperty with argument value.
  3. Return the list-concatenation of propertyNames and nextNames.
AssignmentProperty : IdentifierReference Initializeropt
  1. Let P be StringValue of IdentifierReference.
  2. Let lref be ? ResolveBinding(P).
  3. Let v be ? GetV(value, P).
  4. If Initializeropt is present and v is undefined, then
    1. If IsAnonymousFunctionDefinition(Initializer) is true, then
      1. Set v to ? NamedEvaluation of Initializer with argument P.
    2. Else,
      1. Let defaultValue be ? Evaluation of Initializer.
      2. Set v to ? GetValue(defaultValue).
  5. Perform ? PutValue(lref, v).
  6. Return « P ».
AssignmentProperty : PropertyName : AssignmentElement
  1. Let name be ? Evaluation of PropertyName.
  2. Perform ? KeyedDestructuringAssignmentEvaluation of AssignmentElement with arguments value and name.
  3. Return « name ».

13.15.5.4 Runtime Semantics: RestDestructuringAssignmentEvaluation

The syntax-directed operation RestDestructuringAssignmentEvaluation takes arguments value (an ECMAScript language value) 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:

AssignmentRestProperty : ... DestructuringAssignmentTarget
  1. Let lref be ? Evaluation of DestructuringAssignmentTarget.
  2. Let restObj be OrdinaryObjectCreate(%Object.prototype%).
  3. Perform ? CopyDataProperties(restObj, value, excludedNames).
  4. Return ? PutValue(lref, restObj).

13.15.5.5 Runtime Semantics: IteratorDestructuringAssignmentEvaluation

The syntax-directed operation IteratorDestructuringAssignmentEvaluation takes argument iteratorRecord (an Iterator Record) and returns either a normal completion containing unused or an abrupt completion. It is defined piecewise over the following productions:

AssignmentElementList : AssignmentElisionElement
  1. Return ? IteratorDestructuringAssignmentEvaluation of AssignmentElisionElement with argument iteratorRecord.
AssignmentElementList : AssignmentElementList , AssignmentElisionElement
  1. Perform ? IteratorDestructuringAssignmentEvaluation of AssignmentElementList with argument iteratorRecord.
  2. Return ? IteratorDestructuringAssignmentEvaluation of AssignmentElisionElement with argument iteratorRecord.
AssignmentElisionElement : AssignmentElement
  1. Return ? IteratorDestructuringAssignmentEvaluation of AssignmentElement with argument iteratorRecord.
AssignmentElisionElement : Elision AssignmentElement
  1. Perform ? IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord.
  2. Return ? IteratorDestructuringAssignmentEvaluation of AssignmentElement with argument iteratorRecord.
Elision : ,
  1. If iteratorRecord.[[Done]] is false, then
    1. Let next be Completion(IteratorStep(iteratorRecord)).
    2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(next).
    4. If next is false, set iteratorRecord.[[Done]] to true.
  2. Return unused.
Elision : Elision ,
  1. Perform ? IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord.
  2. If iteratorRecord.[[Done]] is false, then
    1. Let next be Completion(IteratorStep(iteratorRecord)).
    2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(next).
    4. If next is false, set iteratorRecord.[[Done]] to true.
  3. Return unused.
AssignmentElement : DestructuringAssignmentTarget Initializeropt
  1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
    1. Let lref be ? Evaluation of DestructuringAssignmentTarget.
  2. If iteratorRecord.[[Done]] is false, then
    1. Let next be Completion(IteratorStep(iteratorRecord)).
    2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(next).
    4. If next is false, then
      1. Set iteratorRecord.[[Done]] to true.
    5. Else,
      1. Let value be Completion(IteratorValue(next)).
      2. If value is an abrupt completion, set iteratorRecord.[[Done]] to true.
      3. ReturnIfAbrupt(value).
  3. If iteratorRecord.[[Done]] is true, let value be undefined.
  4. If Initializer is present and value is undefined, then
    1. If IsAnonymousFunctionDefinition(Initializer) is true and IsIdentifierRef of DestructuringAssignmentTarget is true, then
      1. Let v be ? NamedEvaluation of Initializer with argument lref.[[ReferencedName]].
    2. Else,
      1. Let defaultValue be ? Evaluation of Initializer.
      2. Let v be ? GetValue(defaultValue).
  5. Else,
    1. Let v be value.
  6. If DestructuringAssignmentTarget is either an ObjectLiteral or an ArrayLiteral, then
    1. Let nestedAssignmentPattern be the AssignmentPattern that is covered by DestructuringAssignmentTarget.
    2. Return ? DestructuringAssignmentEvaluation of nestedAssignmentPattern with argument v.
  7. Return ? PutValue(lref, v).
Note

Left to right evaluation order is maintained by evaluating a DestructuringAssignmentTarget that is not a destructuring pattern prior to accessing the iterator or evaluating the Initializer.

AssignmentRestElement : ... DestructuringAssignmentTarget
  1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
    1. Let lref be ? Evaluation of DestructuringAssignmentTarget.
  2. Let A be ! ArrayCreate(0).
  3. Let n be 0.
  4. Repeat, while iteratorRecord.[[Done]] is false,
    1. Let next be Completion(IteratorStep(iteratorRecord)).
    2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(next).
    4. If next is false, then
      1. Set iteratorRecord.[[Done]] to true.
    5. Else,
      1. Let nextValue be Completion(IteratorValue(next)).
      2. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
      3. ReturnIfAbrupt(nextValue).
      4. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), nextValue).
      5. Set n to n + 1.
  5. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
    1. Return ? PutValue(lref, A).
  6. Let nestedAssignmentPattern be the AssignmentPattern that is covered by DestructuringAssignmentTarget.
  7. Return ? DestructuringAssignmentEvaluation of nestedAssignmentPattern with argument A.

13.15.5.6 Runtime Semantics: KeyedDestructuringAssignmentEvaluation

The syntax-directed operation KeyedDestructuringAssignmentEvaluation takes arguments value (an ECMAScript language value) and propertyName (a property key) and returns either a normal completion containing unused or an abrupt completion. It is defined piecewise over the following productions:

AssignmentElement : DestructuringAssignmentTarget Initializeropt
  1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
    1. Let lref be ? Evaluation of DestructuringAssignmentTarget.
  2. Let v be ? GetV(value, propertyName).
  3. If Initializer is present and v is undefined, then
    1. If IsAnonymousFunctionDefinition(Initializer) and IsIdentifierRef of DestructuringAssignmentTarget are both true, then
      1. Let rhsValue be ? NamedEvaluation of Initializer with argument lref.[[ReferencedName]].
    2. Else,
      1. Let defaultValue be ? Evaluation of Initializer.
      2. Let rhsValue be ? GetValue(defaultValue).
  4. Else,
    1. Let rhsValue be v.
  5. If DestructuringAssignmentTarget is either an ObjectLiteral or an ArrayLiteral, then
    1. Let assignmentPattern be the AssignmentPattern that is covered by DestructuringAssignmentTarget.
    2. Return ? DestructuringAssignmentEvaluation of assignmentPattern with argument rhsValue.
  6. Return ? PutValue(lref, rhsValue).