Stage 1 Draft / May 5, 2023

ES call-this operator (2021)

Introduction

Warning! This spec is out of date!

This is the formal specification for a proposed bind-this operator ~> in JavaScript. 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.

1 Syntax-Directed Operations

1.1 Function Name Inference

1.1.1 Static Semantics: IsFunctionDefinition

Editor's Note

This section augments the original IsFunctionDefinition clause.

SimpleMemberExpression : IdentifierReference SimpleMemberExpression . IdentifierName SimpleMemberExpression . PrivateIdentifier LeftHandSideExpression : BindThisExpression CallExpression OptionalExpression
  1. Return false.

1.1.2 Static Semantics: IsIdentifierRef

Editor's Note

This section augments the original IsIdentifierRef clause.

SimpleMemberExpression : IdentifierReference SimpleMemberExpression . IdentifierName SimpleMemberExpression . PrivateIdentifier ( Expression ) BindThisExpression : MemberExpression ~> SimpleMemberExpression BindThisExpression ~> SimpleMemberExpression
  1. Return false.

1.2 Contains

Editor's Note

This section augments the original Contains clause.

1.2.1 Static Semantics: Contains

With parameter symbol.

SimpleMemberExpression : IdentifierReference
  1. Return false.
SimpleMemberExpression : SimpleMemberExpression . IdentifierName SimpleMemberExpression . PrivateIdentifier
  1. If SimpleMemberExpression Contains symbol is true, return true.
  2. Return false.

1.3 Miscellaneous

1.3.1 Static Semantics: AssignmentTargetType

Editor's Note

This section augments the original AssignmentTargetType clause.

BindThisExpression : MemberExpression ~> SimpleMemberExpression MemberExpression ~> TemplateLiteral BindThisExpression ~> SimpleMemberExpression BindThisExpression ~> TemplateLiteral CallExpression : CoverCallExpressionAndAsyncArrowHead BindThisExpression Arguments SuperCall ImportCall CallExpression Arguments CallExpression [ Expression ] CallExpression . IdentifierName CallExpression ~> SimpleMemberExpression CallExpression TemplateLiteral CallExpression . PrivateIdentifier
  1. Return invalid.

2 ECMAScript Language: Lexical Grammar

2.1 Punctuators

Editor's Note

This section augments the original Punctuators clause.

OtherPunctuator : [empty]

3 ECMAScript Language: Expressions

3.1 Left-Hand-Side Expressions

Editor's Note

This section augments the original Left-Hand-Side Expressions clause.

Syntax

MemberExpression[Yield, Await] : PrimaryExpression[?Yield, ?Await] MemberExpression[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ] MemberExpression[?Yield, ?Await] . IdentifierName MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] SuperProperty[?Yield, ?Await] MetaProperty new MemberExpression[?Yield, ?Await] Arguments[?Yield, ?Await] MemberExpression[?Yield, ?Await] . PrivateIdentifier SimpleMemberExpression[Yield, Await] : IdentifierReference[?Yield, ?Await] SimpleMemberExpression[?Yield, ?Await] . IdentifierName SimpleMemberExpression[?Yield, ?Await] . PrivateIdentifier ( Expression[+In, ?Yield, ?Await] ) NewExpression[Yield, Await] : MemberExpression[?Yield, ?Await] new NewExpression[?Yield, ?Await] BindThisExpression[Yield, Await] : MemberExpression[?Yield, ?Await] ~> SimpleMemberExpression[?Yield, ?Await] MemberExpression[?Yield, ?Await] ~> TemplateLiteral[?Yield, ?Await] BindThisExpression[?Yield, ?Await] ~> SimpleMemberExpression[?Yield, ?Await] BindThisExpression[?Yield, ?Await] ~> TemplateLiteral[?Yield, ?Await] CallExpression[Yield, Await] : CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] BindThisExpression[?Yield, ?Await] Arguments[?Yield, ?Await] SuperCall[?Yield, ?Await] ImportCall[?Yield, ?Await] CallExpression[?Yield, ?Await] Arguments[?Yield, ?Await] CallExpression[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ] CallExpression[?Yield, ?Await] . IdentifierName CallExpression[?Yield, ?Await] ~> SimpleMemberExpression[?Yield, ?Await] CallExpression[?Yield, ?Await] ~> TemplateLiteral[?Yield, ?Await, +Tagged] CallExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] CallExpression[?Yield, ?Await] . PrivateIdentifier SuperCall[Yield, Await] : super Arguments[?Yield, ?Await] ImportCall[Yield, Await] : import ( AssignmentExpression[+In, ?Yield, ?Await] ) Arguments[Yield, Await] : ( ) ( ArgumentList[?Yield, ?Await] ) ( ArgumentList[?Yield, ?Await] , ) ArgumentList[Yield, Await] : AssignmentExpression[+In, ?Yield, ?Await] ... AssignmentExpression[+In, ?Yield, ?Await] ArgumentList[?Yield, ?Await] , AssignmentExpression[+In, ?Yield, ?Await] ArgumentList[?Yield, ?Await] , ... AssignmentExpression[+In, ?Yield, ?Await] OptionalExpression[Yield, Await] : MemberExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] BindThisExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] CallExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] OptionalExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] OptionalChain[Yield, Await] : ?. Arguments[?Yield, ?Await] ?. [ Expression[+In, ?Yield, ?Await] ] ?. IdentifierName ?. ~> SimpleMemberExpression[?Yield, ?Await] ?. TemplateLiteral[?Yield, ?Await, +Tagged] ?. PrivateIdentifier OptionalChain[?Yield, ?Await] Arguments[?Yield, ?Await] OptionalChain[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ] OptionalChain[?Yield, ?Await] . IdentifierName OptionalChain[?Yield, ?Await] ~> SimpleMemberExpression[?Yield, ?Await] [lookahead ≠ .] OptionalChain[?Yield, ?Await] ~> TemplateLiteral[?Yield, ?Await, +Tagged] OptionalChain[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] OptionalChain[?Yield, ?Await] . PrivateIdentifier LeftHandSideExpression[Yield, Await] : NewExpression[?Yield, ?Await] BindThisExpression[?Yield, ?Await] CallExpression[?Yield, ?Await] OptionalExpression[?Yield, ?Await]

3.1.1 Static Semantics

3.1.1.1 Static Semantics: Early Errors

Editor's Note BindThisExpression : MemberExpression ~> TemplateLiteral BindThisExpression ~> TemplateLiteral
  • It is a Syntax Error if any code matches this production.
Note 1

This production exists in order to prevent automatic semicolon insertion rules (11.9) from being applied to the following code with the bind-this operator:

a~>b
`c`

so that it would be interpreted as two valid statements. The purpose is to maintain consistency with similar code without the bind-this operator:

a.b
`c`

which is a valid statement and where automatic semicolon insertion does not apply.

CallExpression : CallExpression ~> TemplateLiteral
  • It is a Syntax Error if any code matches this production.
Note 2

This production exists in order to prevent automatic semicolon insertion rules (11.9) from being applied to the following code with the bind-this operator:

a()~>b
`c`

so that it would be interpreted as two valid statements. The purpose is to maintain consistency with similar code without the bind-this operator:

a().b
`c`

which is a valid statement and where automatic semicolon insertion does not apply.

OptionalChain : OptionalChain ~> TemplateLiteral
  • It is a Syntax Error if any code matches this production.
Note 3

This production exists in order to prevent automatic semicolon insertion rules (11.9) from being applied to the following code with the bind-this operator:

a?.()~>b
`c`

so that it would be interpreted as two valid statements. The purpose is to maintain consistency with similar code without the bind-this operator:

a?.().b
`c`

which is a valid statement and where automatic semicolon insertion does not apply.

3.1.2 Function Calls

This section augments the original Function Calls clause.

3.1.2.1 Runtime Semantics: Evaluation

CallExpression : CoverCallExpressionAndAsyncArrowHead
  1. Let expr be the CallMemberExpression that is covered by CoverCallExpressionAndAsyncArrowHead.
  2. Let memberExpr be the MemberExpression of expr.
  3. Let arguments be the Arguments of expr.
  4. Let ref be the result of evaluating memberExpr.
  5. Let func be ? GetValue(ref).
  6. If ref is a Reference Record, IsPropertyReference(ref) is false, and ref.[[ReferencedName]] is "eval", then
    1. If SameValue(func, %eval%) is true, then
      1. Let argList be ? ArgumentListEvaluation of arguments.
      2. If argList has no elements, return undefined.
      3. Let evalArg be the first element of argList.
      4. If the source code matching this CallExpression is strict mode code, let strictCaller be true. Otherwise let strictCaller be false.
      5. Let evalRealm be the current Realm Record.
      6. Return ? PerformEval(evalArg, evalRealm, strictCaller, true).
  7. Let thisCall be this CallExpression.
  8. Let tailCall be IsInTailPosition(thisCall).
  9. Return ? EvaluateCall(func, ref, arguments, tailCall).
CallExpression : BindThisExpression Arguments Note

See also the bind-this operator.

  1. Let thisExpr be the MemberExpression of BindThisExpression.
  2. Let bindThisRHS be the SimpleMemberExpression of memberExpr.
  3. Let funcExpr be the MemberExpression that is covered by bindThisRHS.
  4. Let thisRef be the result of evaluating thisExpr.
  5. Let thisValue be ? GetValue(thisRef).
  6. Let funcRef be the result of evaluating funcExpr.
  7. Let func be ? GetValue(funcRef).
  8. Let thisCall be this CallExpression.
  9. Let tailCall be IsInTailPosition(thisCall).
  10. Return EvaluateCall(func, thisValue, Arguments, tailCall).
CallExpression : CallExpression Arguments
  1. Let ref be the result of evaluating CallExpression.
  2. Let func be ? GetValue(ref).
  3. Let thisCall be this CallExpression.
  4. Let tailCall be IsInTailPosition(thisCall).
  5. Return ? EvaluateCall(func, ref, Arguments, tailCall).

3.1.3 Bind-this operator

Editor's Note

This section is a wholly new subclause to be inserted after the new Operator clause.

3.1.3.1 Runtime Semantics: Evaluation

3.1.3.1.1 Runtime Semantics: Evaluation

Note

For evaluation of the production CallExpression : BindThisExpression Arguments , see clause 3.1.2.1.

For evaluation of the productions OptionalChain : ?. ~> SimpleMemberExpression and OptionalChain : OptionalChain ~> SimpleMemberExpression , see clause 3.1.2.1.

BindThisExpression : MemberExpression ~> SimpleMemberExpression
  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let funcExpr be the MemberExpression that is covered by SimpleMemberExpression.
  4. Let funcRef be the result of evaluating funcExpr.
  5. Let func be ? GetValue(funcRef).
  6. Return BindThis(baseValue, func).
BindThisExpression : BindThisExpression ~> SimpleMemberExpression
  1. Let baseReference be the result of evaluating BindThisExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let funcExpr be the MemberExpression that is covered by SimpleMemberExpression.
  4. Let funcRef be the result of evaluating funcExpr.
  5. Let func be ? GetValue(funcRef).
  6. Return BindThis(baseValue, func).
CallExpression : CallExpression ~> SimpleMemberExpression
  1. Let baseReference be the result of evaluating CallExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let funcExpr be the MemberExpression that is covered by SimpleMemberExpression.
  4. Let funcRef be the result of evaluating funcExpr.
  5. Let func be ? GetValue(funcRef).
  6. Return BindThis(baseValue, func).

3.1.3.1.2 BindThis ( baseValue, func )

The abstract operation BindThis takes arguments baseValue (an ECMAScript language value) and func (another ECMAScript language value). It performs the following steps when called:

  1. If IsCallable(func) is false, throw a TypeError exception.
  2. Let F be ? BoundFunctionCreate(func, baseValue, « »).
  3. Let L be 0.
  4. Let methodHasLength be ? HasOwnProperty(method, "length").
  5. If methodHasLength is true, then
    1. Let methodLen be ? Get(method, "length").
    2. If Type(methodLen) is Number, then
      1. If methodLen is +∞𝔽, set L to +∞.
      2. Else if methodLen is -∞𝔽, set L to 0.
      3. Else,
        1. Let methodLenAsInt be ! ToIntegerOrInfinity(methodLen).
        2. Assert: methodLenAsInt is finite.
        3. Set L to max(methodLenAsInt, 0).
  6. Perform ! SetFunctionLength(F, L).
  7. Let methodName be ? Get(method, "name").
  8. If Type(methodName) is not String, set methodName to the empty String.
  9. Perform SetFunctionName(F, methodName, "bound").
  10. Return F.
Note

Function objects created using the bind-this operator are exotic objects. They also do not have a "prototype" property.

3.1.4 Optional Chains

Editor's Note

This section augments the original Optional Chains clause.

3.1.4.1 Runtime Semantics: Evaluation

OptionalExpression : MemberExpression OptionalChain
  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. If baseValue is undefined or null, then
    1. Return undefined.
  4. Return the result of performing ChainEvaluation of OptionalChain with arguments baseValue and baseReference.
OptionalExpression : BindThisExpression OptionalChain
  1. Let baseReference be the result of evaluating BindThisExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. If baseValue is undefined or null, then
    1. Return undefined.
  4. Return the result of performing ChainEvaluation of OptionalChain with arguments baseValue and baseReference.
OptionalExpression : CallExpression OptionalChain
  1. Let baseReference be the result of evaluating CallExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. If baseValue is undefined or null, then
    1. Return undefined.
  4. Return the result of performing ChainEvaluation of OptionalChain with arguments baseValue and baseReference.
OptionalExpression : OptionalExpression OptionalChain
  1. Let baseReference be the result of evaluating OptionalExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. If baseValue is undefined or null, then
    1. Return undefined.
  4. Return the result of performing ChainEvaluation of OptionalChain with arguments baseValue and baseReference.

3.1.4.2 Runtime Semantics: ChainEvaluation

The syntax-directed operation ChainEvaluation takes arguments baseValue and baseReference. It is defined piecewise over the following productions:

OptionalChain : ?. Arguments
  1. Let thisChain be this OptionalChain.
  2. Let tailCall be IsInTailPosition(thisChain).
  3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
OptionalChain : ?. [ Expression ]
  1. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
  2. Return ? EvaluatePropertyAccessWithExpressionKey(baseValue, Expression, strict).
OptionalChain : ?. IdentifierName
  1. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
  2. Return ! EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict).
OptionalChain : ?. ~> SimpleMemberExpression Note 1

See also the bind-this operator.

  1. Let funcExpr be the MemberExpression that is covered by SimpleMemberExpression.
  2. Let funcRef be the result of evaluating funcExpr.
  3. Let func be ? GetValue(funcRef).
  4. Return BindThis(baseValue, func).
OptionalChain : ?. PrivateIdentifier
  1. Let fieldNameString be the StringValue of PrivateIdentifier.
  2. Return ! MakePrivateReference(baseValue, fieldNameString).
OptionalChain : OptionalChain Arguments
  1. Let optionalChain be OptionalChain.
  2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
  3. Let newValue be ? GetValue(newReference).
  4. Let thisChain be this OptionalChain.
  5. Let tailCall be IsInTailPosition(thisChain).
  6. Return ? EvaluateCall(newValue, newReference, Arguments, tailCall).
Note 2

If OptionalChain (in OptionalChain : OptionalChain Arguments ) is, in turn, covering the production OptionalChain : ?. ~> SimpleMemberExpression , then the preceding algorithm is indistinguishable from the following:

  1. Let optionalBindThisChain be the OptionalChain : ?. ~> SimpleMemberExpression that is covered by OptionalChain.
  2. Let bindThisRHS be the SimpleMemberExpression of optionalBindThisChain.
  3. Let funcExpr be the MemberExpression that is covered by bindThisRHS.
  4. Let funcRef be the result of evaluating funcExpr.
  5. Let func be ? GetValue(funcRef).
  6. Let thisChain be this OptionalChain.
  7. Let tailCall be IsInTailPosition(thisChain).
  8. Return EvaluateCall(func, baseValue, Arguments, tailCall).

If OptionalChain (in OptionalChain : OptionalChain Arguments ) is, in turn, covering the production OptionalChain : OptionalChain ~> SimpleMemberExpression , then the preceding algorithm is indistinguishable from the following:

  1. Let bindThisOptionalChain be the OptionalChain : OptionalChain ~> SimpleMemberExpression that is covered by OptionalChain.
  2. Let bindThisRHS be the SimpleMemberExpression of bindThisOptionalChain.
  3. Let funcExpr be the MemberExpression that is covered by bindThisRHS.
  4. Let thisRef be the result of evaluating ? ChainEvaluation of thisOptionalChain with arguments baseValue and baseReference.
  5. Let thisValue be ? GetValue(thisRef).
  6. Let funcRef be the result of evaluating funcExpr.
  7. Let func be ? GetValue(funcRef).
  8. Let thisChain be this OptionalChain.
  9. Let tailCall be IsInTailPosition(thisChain).
  10. Return EvaluateCall(func, thisValue, Arguments, tailCall).
OptionalChain : OptionalChain [ Expression ]
  1. Let optionalChain be OptionalChain.
  2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
  3. Let newValue be ? GetValue(newReference).
  4. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
  5. Return ? EvaluatePropertyAccessWithExpressionKey(newValue, Expression, strict).
OptionalChain : OptionalChain . IdentifierName
  1. Let optionalChain be OptionalChain.
  2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
  3. Let newValue be ? GetValue(newReference).
  4. If the code matched by this OptionalChain is strict mode code, let strict be true; else let strict be false.
  5. Return ! EvaluatePropertyAccessWithIdentifierKey(newValue, IdentifierName, strict).
OptionalChain : OptionalChain ~> SimpleMemberExpression Note 3

See also the bind-this operator.

  1. Let optionalChain be OptionalChain.
  2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
  3. Let newValue be ? GetValue(newReference).
  4. Let funcExpr be the MemberExpression that is covered by SimpleMemberExpression.
  5. Let funcRef be the result of evaluating funcExpr.
  6. Let func be ? GetValue(funcRef).
  7. Return BindThis(newValue, func).
OptionalChain : OptionalChain . PrivateIdentifier
  1. Let optionalChain be OptionalChain.
  2. Let newReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
  3. Let newValue be ? GetValue(newReference).
  4. Let fieldNameString be the StringValue of PrivateIdentifier.
  5. Return ! MakePrivateReference(newValue, fieldNameString).