GitHub - js-choi/proposal-function-demethodize: Draft specification for a standard demethodize function in JavaScript. (original) (raw)
Demethodize function for JavaScript
ECMAScript Stage-0 Proposal. J. S. Choi, 2022.
- Formal specification: Not yet
- Babel plugin: Not yet
- Proposal history
Rationale
The dynamic this
binding is a fundamental part of JavaScript design and practice today. Many APIs use the this
binding functionally as another “argument” to their functions. Because of this, developers frequently need to change the this
binding. However, dynamic prototype-based dispatch may often be undesirable, and using a .call.bind()
method is frequent in many codebases.
We therefore propose exploring the addition of an API to the JavaScript language that would convert this
-based methods into ordinary functions that do not use this
.
If this proposal is approved for Stage 1, then we would explore various directions for the API’s design. We would also assemble as many real-world use cases as possible and shape our design to fulfill them.
In addition, if we would explore cross-cutting concerns and overlap with the proposed call-this syntax and other dataflow proposals.
Description
The Function.prototype.demethodize
method would create a new function that calls the original function, supplying its first argument as the original function’s this
receiver, and supplying the rest of its arguments as the original function’s ordinary arguments.
This is useful for converting this
-based functions into non-this
-based functions.
fn.demethodize();
const $slice = Array.prototype.slice.demethodize(); $slice([ 0, 1, 2 ], 1); // [ 1, 2 ].
This is not a substitute for a call-this syntax, which allows developers to change the receiver of functions without creating a wrapper function.
fn.demethodize()
is equivalent toFunction.prototype.call.bind(fn)
and toFunction.prototype.bind.bind(Function.prototype.call)(fn)
.
Therefore, fn.demethodize()(thisArg, ...restArgs)
is equivalent tofn.call(thisArg, ...restArgs)
.
The following real-world example originally used call-bind or a manually created similar function.
// From chrome-devtools-frontend@1.0.934332 // node_modules/array-includes/test/implementation.js. runTests(implementation.demethodize(), t);
// From string.prototype.trimstart@1.0.4/index.js: var bound = getPolyfill().demethodize();
// From andreasgal/dom.js (84b7ab6) src/snapshot.js. const /* … / join = A.join || Array.prototype.join.demethodize(), map = A.map || Array.prototype.map.demethodize(), push = A.push || Array.prototype.push.demethodize(), / … */;
Precedents include:
- call-bind:
callBind