{"id":18137815,"url":"https://github.com/tc39/proposal-call-this","last_synced_at":"2025-04-16T01:23:40.286Z","repository":{"id":42586927,"uuid":"392462646","full_name":"tc39/proposal-call-this","owner":"tc39","description":"A proposal for a simple call-this operator in JavaScript.","archived":false,"fork":false,"pushed_at":"2023-05-05T18:26:02.000Z","size":2007,"stargazers_count":124,"open_issues_count":6,"forks_count":5,"subscribers_count":33,"default_branch":"main","last_synced_at":"2025-03-29T03:23:24.611Z","etag":null,"topics":["javascript","proposal","tc39"],"latest_commit_sha":null,"homepage":"https://tc39.es/proposal-call-this/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tc39.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-03T21:36:46.000Z","updated_at":"2025-03-28T03:36:30.000Z","dependencies_parsed_at":"2024-11-16T16:04:06.131Z","dependency_job_id":"1cf6f876-df08-4afd-8ac0-7ed7c85f741d","html_url":"https://github.com/tc39/proposal-call-this","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-call-this","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-call-this/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-call-this/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-call-this/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tc39","download_url":"https://codeload.github.com/tc39/proposal-call-this/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249179805,"owners_count":21225606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","proposal","tc39"],"created_at":"2024-11-01T15:07:04.300Z","updated_at":"2025-04-16T01:23:40.268Z","avatar_url":"https://github.com/tc39.png","language":"HTML","funding_links":[],"categories":["HTML"],"sub_categories":[],"readme":"# Call-this operator for JavaScript\nECMAScript Stage-1 Proposal. J. S. Choi, 2021.\n\n* **[Formal specification][]**\n* Babel plugin: Not yet\n\n[formal specification]: https://tc39.es/proposal-call-this/\n\nThis proposal is a **resurrection** of the old [Stage-0 bind-operator\nproposal][old bind]. It is also an alternative, **competing** proposal to the\n[Stage-1 extensions proposal][extensions]. For more information, see [§ Related\nproposals](#related-proposals).\n\n[old bind]: https://github.com/tc39/proposal-bind-operator\n[extensions]: https://github.com/tc39/proposal-extensions\n\n## Syntax\n\nThe syntax is being bikeshedded in [issue #10][].\n\n[issue #10]: https://github.com/tc39/proposal-call-this/issues/10\n\n\u003cdetails\u003e\n\u003csummary\u003eTentative syntax\u003c/summary\u003e\n\n```js\nreceiver~\u003efn(arg0, arg1)\nreceiver~\u003ens.fn(arg0, arg1)\nreceiver~\u003e(expr)(arg0, arg1)\n```\n\n\u003cdl\u003e\n\n\u003cdt\u003e\u003ccode\u003ereceiver\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\n\nA member expression, a call expression, an optional expression, a `new`\nexpression with arguments, another call-this expression, or a parenthesized\nexpression. The value to which this expression resolves will be bound to the\nright-hand side’s function object, as that function’s `this` receiver.\n\n\u003c/dd\u003e\n\n\u003cdt\u003e\u003ccode\u003efn\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\n\nA variable that must resolve to a function object.\n\n\u003c/dd\u003e\n\n\u003cdt\u003e\u003ccode\u003ens\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\n\nInstead of a single variable, the right-hand side may be a namespace object’s\nvariable, followed by a chain of property identifiers. This chain must resolve\nto a function object.\n\n\u003c/dd\u003e\n\n\u003cdt\u003e\u003ccode\u003eexpr\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\n\nAn arbitrary expression within parentheses,\nwhich must resolve to a function object.\n\n\u003c/dd\u003e\n\n\u003cdt\u003e\u003ccode\u003earg0, arg1\u003c/code\u003e, etc.\u003c/dt\u003e\n\u003cdd\u003e\n\nA series of argument expressions, which may include spread `...` syntax.\n\n\u003c/dd\u003e\n\n\u003c/dl\u003e\n\n\u003c/details\u003e\n\n## Description\n\nThe syntax is being bikeshedded in [issue #10][].\n\n[issue #10]: https://github.com/tc39/proposal-call-this/issues/10\n\n\u003cdetails\u003e\n\u003csummary\u003eTentative description\u003c/summary\u003e\n\n(A [formal specification][] is available.)\n\nThe call-this operator `~\u003e` is a **left-associative** binary operator. It calls\nits right-hand side (a **function**), binding its `this` value to its left-hand\nside (a **receiver** value), as well well as any given arguments – in the same\nmanner as [`Function.prototype.call`][call].\n\nFor example, `receiver~\u003efn(arg0, arg1)` would be equivalent to\n`fn.call(receiver, arg0, arg1)` (except that its behavior does not change if\ncode elsewhere reassigns the global method `Function.prototype.call`).\n\nLikewise, `receiver~\u003e(createFn())(arg0, arg1)` would be roughly equivalent to\n`createFn().call(receiver, arg0, arg1)`.\n\nIf the operator’s right-hand side does not evaluate to a function during\nruntime, then the program throws a TypeError.\n\nThe operator’s **left** side has equal **[precedence][]** with member\nexpressions, call expressions, `new` expressions with arguments, and optional\nexpressions. Like those operators, the call-this operator also may be\nshort-circuited by optional expressions in its left-hand side.\n\n[precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence\n\n| Left-hand side                  | Example            | Grouping\n| ------------------------------- | ------------------ | --------------------\n| Member expressions              |`obj.prop~\u003efn(a)` |`(obj.prop)~\u003efn(a)`\n| Call expressions                |`obj()~\u003efn(a)`    |`(obj())~\u003efn(a)`\n| Optional expressions            |`obj?.prop~\u003efn(a)`|`(obj?.prop)~\u003efn(a)`\n|`new` expressions with arguments |`new C()~\u003efn(a)`  |`(new C())~\u003efn(a)`\n\nThe operator’s **right**-hand side, as with decorators, may be one of\nthe following:\n* A single **identifier** or **private field** (like `fn` or `#field`).\n* A **chain** of identifiers and/or private fields (like `ns.fn` or `this.ns.#field`).\n* A parenthesized **expression** (like `(createFn())`).\n\nFor example, `receiver~\u003ens.ns.ns.fn` groups as `receiver~\u003e(ns.ns.ns.fn)`.\n\nSimilarly to the `.` and `?.` operators,\nthe call-this operator may be **padded** by whitespace or not.\\\nFor example, `receiver~\u003efn`\\\nis equivalent to `receiver~\u003efn`,\\\nand `receiver~\u003e(createFn())`\\\nis equivalent to `receiver~\u003e(createFn())`.\n\nThe call-this operator may be optionally chained with `?.` (i.e., `?.~\u003e`):\\\n`receiver~\u003efn` will always result in a bound function,\nregardless of whether `receiver` is nullish.\\\n`receiver ?.~\u003efn` will result in `null` or `undefined`\nif `receiver` is `null` or `undefined`.\\\n`receiver ?.~\u003efn(arg)` also short-circuits as usual, before `arg` is\nevaluated, if `receiver` is nullish.\n\nA `new` expression may **not** contain a call-this expression without\nparentheses. `new x~\u003efn()` is a SyntaxError.\nOtherwise, `new x~\u003efn()` would be visually ambiguous between\\\n`(new x)~\u003efn()` and `new (x~\u003efn())`.\n\n\u003c/details\u003e\n\n## Why a call-this operator\nIn short:\n\n1. [`.call`][call] is very useful and very common in JavaScript codebases.\n2. But `.call` is clunky and unergonomic.\n\n[bind]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind\n[call]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call\n\n### `.call` is very common\nThe dynamic `this` binding is a fundamental part of JavaScript design and\npractice today. Because of this, developers frequently need to change the\n`this` binding. `.call` is arguably one of the most commonly used functions in\nall of JavaScript.\n\nWe can estimate `.call`’s prevalences using [Node Gzemnid][]. Although [Gzemnid\ncan be deceptive][], we are only seeking rough estimations.\n\n[Node Gzemnid]: https://github.com/nodejs/Gzemnid\n[Gzemnid can be deceptive]: https://github.com/nodejs/Gzemnid/blob/main/README.md#deception\n\nThe following results are from the checked-in-Git source code of the top-1000\ndownloaded NPM packages.\n\n| Occurrences | Method      |\n| ----------: | ----------- |\n| 1,016,503   |`.map`       |\n| 701,169     |`.push`      |\n| 315,922     |**`.call`**  |\n| 271,915     |`console.log`|\n| 182,292     |`.slice`     |\n| 170,248     |`.bind`      |\n| 168,872     |`.set`       |\n\nThese results suggest that usage of `.call` is comparable to usage of other\nfrequently used standard functions. In this dataset, its usage exceeds even\nthat of `console.log`.\n\nObviously, [this methodology has many pitfalls][Gzemnid can be deceptive], but\nwe are only looking for roughly estimated orders of magnitude relative to other\nbaseline functions. Gzemnid counts each library’s codebase only once; it does\nnot double-count dependencies.\n\n\u003cdetails\u003e\n\n\u003csummary\u003eWhat methodology was used to get these results?\u003c/summary\u003e\n\n***\n\nFirst, we download the 2019-06-04 [pre-built Gzemnid dataset][] for the top-1000\ndownloaded NPM packages. We also need Gzemnid’s `search.topcode.sh` script in\nthe same active directory, which in turn requires the lz4 command suite.\n`search.topcode.sh` will output lines of code from the top-1000 packages that\nmatch the given regular expression.\n\n[pre-built Gzemnid dataset]: https://gzemnid.nodejs.org/datasets/\n\n```bash\n./search.topcode.sh '\\.call\\b' | head\ngrep -aE  \"\\.call\\b\"\n177726827\tdebug@4.1.1/src/common.js:101:\t\t\t\t\tmatch = formatter.call(self, val);\n177726827\tdebug@4.1.1/src/common.js:111:\t\t\tcreateDebug.formatArgs.call(self, args);\n154772106\tkind-of@6.0.2/index.js:54:  type = toString.call(val);\n139612972\treadable-stream@3.4.0/errors-browser.js:26:      return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;\n139612972\treadable-stream@3.4.0/lib/_stream_duplex.js:60:  Readable.call(this, options);\n139612972\treadable-stream@3.4.0/lib/_stream_duplex.js:61:  Writable.call(this, options);\n139612972\treadable-stream@3.4.0/lib/_stream_passthrough.js:34:  Transform.call(this, options);\n139612972\treadable-stream@3.4.0/lib/_stream_readable.js:183:  Stream.call(this);\n139612972\treadable-stream@3.4.0/lib/_stream_readable.js:786:  var res = Stream.prototype.on.call(this, ev, fn);\n```\n\nWe use `awk` to count those matching lines of code and compare their numbers\nfor `call` and several other frequently used functions.\n\n```bash\n\u003e ls\nsearch.topcode.sh\nslim.topcode.1000.txt.lz4\n\u003e ./search.topcode.sh '\\.call\\b' | grep -E --invert-match '//.*\\.call|/\\*.+\\.call|[^a-zA-Z][A-Z][a-zA-Z0-9_$]*\\.call\\( *this|_super\\.call|_super\\.prototype\\.|_getPrototypeOf|_possibleConstructorReturn|__super__|WEBPACK VAR INJECTION|_objectWithoutProperties|\\.hasOwnProperty\\.call' | awk 'END { print NR }'\n315922\n\u003e ./search.topcode.sh '\\.bind\\b' | awk 'END { print NR }'\n170248\n\u003e ./search.topcode.sh '\\b.map\\b' | awk 'END { print NR }'\n1016503\n\u003e ./search.topcode.sh '\\bconsole.log\\b' | awk 'END { print NR }'\n271915\n\u003e ./search.topcode.sh '\\.slice\\b' | awk 'END { print NR }'\n182292\n\u003e ./search.topcode.sh '\\.set\\b' | awk 'END { print NR }'\n168872\n\u003e ./search.topcode.sh '\\.push\\b' | awk 'END { print NR }'\n701169\n```\n\nNote that, for `.call`, we use `grep` to exclude several irrelevant occurrences\nof `.call` either within comments or from transpiled code. We err on the side of\nfalse exclusions.\n\n| Excluded pattern                             | Reason                                           |\n| -------------------------------------------- | ------------------------------------------------ |\n| `//.*\\.call`                                 | Code comment.                                    |\n| `/\\*.+\\.call`                                | Code comment.                                    |\n| `[^a-zA-Z][A-Z][a-zA-Z0-9_$]*\\.call\\( *this` | Constructor call obsoleted by `super`. See note. |\n| `_super\\.call`                               | Babel-transpiled `super()` artifact.             |\n| `_super\\.prototype\\.`                        | Babel-transpiled `super.fn()` artifact.          |\n| `_objectWithoutProperties`                   | Babel-transpiled `...` artifact.                 |\n| `_getPrototypeOf`                            | Babel artifact.                                  |\n| `_possibleConstructorReturn`                 | Babel artifact.                                                |\n| `__super__`                                  | CoffeeScript artifact.                           |\n| `WEBPACK VAR INJECTION`                      | Webpack artifact.                                |\n| `\\.hasOwnProperty\\.call`                     | Obsoleted by `Object.has`.                       |\n\nThese excluded patterns were determined by an independent investigator ([Scott\nJamison][]), after [manually reviewing the first 10,000 occurrences of `.call`\nin the dataset][review] for why each occurrence occurred.\n\n[review]: https://github.com/tc39/proposal-call-this/issues/12\n\nThe excluded `[^a-zA-Z][A-Z][a-zA-Z0-9_$]*\\.call\\( *this` pattern deserves a\nspecial note. This pattern matches any capitalized identifier followed by\n`.call(this`. We exclude any such occurrences because any capitalized identifier\nlikely refers to a constructor, and using `.call` on a constructor is a pattern\nthat has largely been obviated by `class` and `super` syntax. It is likely that\nthis pattern erroneously excludes many legitimate uses of `.call` from our\ncount, but this bias against `.call` is acceptable for the purposes of rough\ncomparison.\n\n[Scott Jamison]: https://github.com/theScottyJam\n\n\u003c/details\u003e\n\n***\n\nThere are a variety of reasons why developers use `.call`. These include:\n\n**Wrapping** a receiver’s method before calling it:\n\n```js\n// Wrapping a receiver’s method before calling it:\nassertFunction(obj.f).call(obj, f);\n\n// From bluebird@3.5.5.\ntryCatch(item).call(boundTo, e);\n```\n\n**Conditionally switching** a call between two methods:\n\n```js\nconst method = obj.f ?? obj.g;\nmethod.call(obj, arg0, arg1);\n\n// From debug@4.1.1.\n// createDebug is an object either for Node or for web browsers.\ncreateDebug.formatArgs.call(self, args);\n```\n\n**Reusing** an **original** method on a **monkey-patched** object:\n\n```js\n// From graceful-fs@4.1.15.\nreturn fs$read.call(fs, fd, /*…*/)\n```\n\n**Protecting** a method call from **prototype pollution**:\n```js\n// From lodash@4.17.11.\n// Object.prototype.toString was cached as nativeObjectToString.\nnativeObjectToString.call(value);\n```\n\n…and other reasons. Developers do all of this using `.call`, and the sum of\nthese uses propels `.call` to being one of the most used operations in the\nentire language.\n\n### `.call` is clunky\nIn spite of its frequency, .call is clunky and poorly readable. It separates the function from its receiver and arguments with boilerplate, and it flips the “natural” word order, resulting in a verb`.call`–subject–object word order:\n\n```js\nfn.call(rec, arg0).\n```\n\nJavaScript developers are used to using methods in a [subject–verb–object word\norder][] that resembles English and other [SVO human languages][]. This pattern\nis ubiquitous in JavaScript as dot method calls:\n\n```js\nrec.method(arg0).\n```\n\n[subject–verb–object word order]: https://en.wikipedia.org/wiki/Subject–verb–object\n[SVO human languages]: https://en.wikipedia.org/wiki/Category:Subject–verb–object_languages\n\nConsider the following real-life code using `.call`, and compare them\nto versions that use the call-this operator. The difference is especially\nevident when you read them aloud.\n\n```js\n// kind-of@6.0.2/index.js\ntype = toString.call(val);\ntype = val~\u003etoString();\n\n// debug@4.1.1/src/common.js\nmatch = formatter.call(self, val);\nmatch = self~\u003eformatter(val);\n\ncreateDebug.formatArgs.call(self, args);\nself~\u003ecreateDebug.formatArgs(args);\n\n// rxjs@6.5.2/src/internal/operators/every.ts\nresult = this.predicate.call(this.thisArg, value, this.index++, this.source);\nresult = this.thisArg~\u003ethis.predicate(value, this.index++, this.source);\n\n// bluebird@3.5.5/js/release/synchronous_inspection.js\nreturn isPending.call(this._target());\nreturn this._target()~\u003eisPending();\n\nvar matchesPredicate = tryCatch(item).call(boundTo, e);\nvar matchesPredicate = boundTo~\u003e(tryCatch(item))(e);\n\n// async@3.0.1/internal/initialParams.js\nvar callback = args.pop(); return fn.call(this, args, callback);\nvar callback = args.pop(); return this~\u003efn(args, callback);\n\n// ajv@6.10.0/lib/ajv.js\nvalidate = macro.call(self, schema, parentSchema, it);\nvalidate = self~\u003emacro(schema, parentSchema, it);\n\n// graceful-fs@4.1.15/polyfills.js\nreturn fs$read.call(fs, fd, buffer, offset, length, position, callback)\nreturn fs~\u003efs$read(fd, buffer, offset, length, position, callback)\n```\n\nIn short:\n\n**Very common\n× Very clunky\n= Worth improving with syntax**.\n\n## Concerns about ecosystem schism\n\u003e The answer to whether multiple ways or syntaxes of doing something are\n\u003e harmful critically depends on the duplication’s effect on APIs and how viral\n\u003e it is.\n\u003e\n\u003e Suppose we’re considering having two syntaxes 𝘟 and 𝘠 to use APIs. If\n\u003e module or person 𝘈 uses syntax 𝘟 which interoperates better with syntax 𝘟\n\u003e than syntax 𝘠 and that pressures module or person 𝘉 to use syntax 𝘟 in\n\u003e their new APIs to interoperate with person 𝘈’s APIs, that virality\n\u003e encourages ecosystem forking and API wars. Introducing multiple such ways\n\u003e into the language is bad.\n\u003e\n\u003e “On the other hand, if person 𝘈’s choice of syntax [i.e., 𝘟] has no effect\n\u003e on person 𝘉[’s choice of syntax, 𝘠,] and they can interoperate without any\n\u003e hassles, then that’s generally benign.”\n\n[From the 2022-01-27 dataflow meeting](https://github.com/tc39/incubator-agendas/blob/main/notes/2022/01-27.md#tmtowtdi-and-overlap-between-hack-pipes-and-bind-this).\n\n* **𝘟**: Some APIs (like “**functional**” APIs) use non-`this`-based ƒs.\n* **𝘠**: Some APIs (like “**object-oriented**” APIs) use `this`-based ƒs.\n\nThis schism between 𝘟 APIs and 𝘠 APIs is already is built into the language.\nThe schism is such that prominent APIs like the [Firebase JS SDK have\nswitched][] from 𝘠 to 𝘟 (e.g., for module splitting).\n\n[Firebase JS SDK have switched]: https://firebase.blog/posts/2021/08/deep-dive-into-the-new-firebase-js-sdk-design\n\nBut the call-this operator, together with the [pipe operator `|\u003e`][pipe\noperator], would make interoperability between 𝘟 and 𝘠 more fluid – and it\nwould make the choice between 𝘟 and 𝘠 less viral – bridging the schism:\n\n```js\nimport { x0, x1 } from '𝘟';\nimport { y0, y1 } from '𝘠';\ninput |\u003e x0(@)~\u003ey0() |\u003e x1(@)~\u003ey1();\n```\n\n## Non-goals\nA goal of this proposal is **simplicity**. Therefore, this proposal\npurposefully does *not* address the following use cases:\n\n**Function binding** and **method extraction** are not a goal of this proposal.\n\nChanging the `this` receiver of functions is more common than function binding,\nas evidenced by the preceding statistics. Some TC39 representatives have\nexpressed concern that function binding may be redundant with proposals such as\n[PFA (partial function application) syntax][PFA]. Therefore, we will defer\nthese two features to future proposals.\n\n**Extracting property accessors** (i.e., getters and setters) is also not a\ngoal of this proposal. Get/set accessors are **not like** methods. Methods are\n**properties** (which happen to be functions). Accessors themselves are **not**\nproperties; they are functions that activate when getting or setting\nproperties.\n\nGetters/setters have to be extracted using `Object.getOwnPropertyDescriptor`;\nthey are not handled in a special way. This verbosity may be considered to be\ndesirable [syntactic salt][]: it makes the developer’s intention (to extract\ngetters/setters – and not methods) more explicit.\n\n```js\nconst { get: $getSize } =\n  Object.getOwnPropertyDescriptor(\n    Set.prototype, 'size');\n\n// The adversary’s code.\ndelete Set; delete Function;\n\n// Our own trusted code, running later.\nnew Set([0, 1, 2])~\u003e$getSize();\n```\n\n[syntactic salt]: https://en.wikipedia.org/wiki/Syntactic_sugar#Syntactic_salt\n\n**Function/expression application**, in which deeply nested function calls and\nother expressions are untangled into linear pipelines, is important but not\naddressed by this proposal. Instead, it is addressed by the [pipe operator][],\nwith which this proposal’s syntax works well.\n\n[pipe operator]: #pipe-operator\n\n## Related proposals\n\n### Old bind operator\nThis proposal is a **resurrection** of the old [Stage-0 bind-operator\nproposal][old bind]. (A champion of the old proposal has [recommended restarting\nwith a new proposal][fresh] instead of using the old proposal.)\n\n[fresh]: https://github.com/tc39/proposal-bind-operator/issues/56#issuecomment-698444297\n\nThe new proposal is basically the same as the old proposal. The only big\ndifference is that there is no unary form for implicit binding of the receiver\nduring method extraction. (See also [non-goals](#non-goals).)\n\n### Extensions\nThe extensions system is an alternative, **competing** proposal to the [Stage-1\nextensions proposal][extensions].\n\nAn [in-depth comparison is also available][extensions compare]. The concrete\ndifferences briefly are:\n\n1. Call-this has no special variable namespace.\n2. Call-this has no implicit syntactic handling of property accessors.\n3. Call-this has no polymorphic `const ::{ … } from …;` syntax.\n4. Call-this has no polymorphic `…::…:…` syntax.\n5. Call-this has no `Symbol.extension` metaprogramming system.\n\n[extensions compare]: https://github.com/js-choi/proposal-call-this/blob/main/extensions-comparison.md\n\n### Pipe operator\nThe [pipe operator][pipe repo] is a **complementary** proposal that can be used\nto linearize deeply nested expressions like `f(0, g([h()], 1), 2)` into\n`h() |\u003e g(^, 1) |\u003e f(0, ^, 2)`.\n\nThis is fundamentally different than the call-this operator’s purpose, which\nwould be much closer to property access `.`.\n\nIt is true that property access `.`, call-this, and the pipe operator all may be\nused to linearize code. But this is a mere happy side effect for the first two\noperators:\n\n* Property access is tightly coupled to object membership.\n* Call-this is simply changes the `this` binding of a function call.\n\nIn contrast, the pipe operator is designed to generally linearize all other\nkinds of expressions.\n\n`|\u003e` does not improve .call’s clunkiness. Here is the clunky (and frequent)\nstatus quo again:\n\n```js\nfn.call(rec, arg0)\n```\n\nIntroducing the [pipe operator `|\u003e`][pipe operator] fixes **word order**, but the result is even **less** readable. Excessive boilerplate separates the function from its receiver and arguments:\n\n```js\nrec |\u003e fn.call(@, arg0) // Less readable.\n```\n\nOnly a separate operator can improve the word order without otherwise\ncompromising readability:\n\n```js\nrec~\u003efn(arg0)\n```\n\nThe pipe champion group have been investigating whether it is possible to\nmodify the pipe operator to address .call’s clunkiness while still addressing\npipe’s other use cases (e.g., non-this-based, n-ary function calls; async\nfunction calls). It has still found none except a separate operator.\n\nJust like how the pipe operator coexists with property access:\n```js\n// Adapted from react@17.0.2/scripts/jest/jest-cli.js\nObject.keys(envars)\n  .map(envar =\u003e `${envar}=${envars[envar]}`)\n  .join(' ')\n  |\u003e `$ ${^}`\n  |\u003e chalk.dim(^, 'node', args.join(' '))\n  |\u003e console.log(^);\n```\n\n…so too can it work together with call-this:\n```js\n// Adapted from chalk@2.4.2/index.js\nreturn this._styles\n  |\u003e (^ ? ^.concat(codes) : [codes])\n  |\u003e this~\u003ebuild(^, this._empty, key);\n```\n\n[pipe repo]: https://github.com/tc39/proposal-pipeline-operator\n\n### PFA syntax\n[PFA (partial function application) syntax][PFA] `~()` would tersely create\npartially applied functions.\n\nPFA syntax `~()` and call-this `~\u003e` are also complementary and handle different\nuse cases.\n\nFor example, `obj.method~()` would handle method extraction with implicit\nbinding, which call-this does not address. In other words, when the receiver\nobject itself contains the function to which we wish to bind, then we need to\nrepeat the receiver once, with call-this. PFA syntax would allow us to avoid\nrepeating the receiver.\n\n```js\nn.on(\"click\", v.reset.bind(v))\nn.on(\"click\", v.reset~())\n```\n\nIn contrast, call-this changes the receiver of a function call.\n`receiver~\u003efn()`. (This unbound function might have already been extracted\nfrom another object.) PFA syntax does not address this use case.\n\n```js\n// bluebird@3.5.5/js/release/synchronous_inspection.js\nisPending.call(this._target())\nthis._target()~\u003eisPending()\n```\n\n[PFA]: https://github.com/tc39/proposal-partial-application\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-call-this","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftc39%2Fproposal-call-this","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-call-this/lists"}