Suggestion : "automatic" context binding
# T.J. Crowder (8 years ago)
This already has a Stage 0 proposal here: tc39/proposal-bind-operator.
You can find all proposals at tc39/proposals in (currently) three categories: That page itself, which lists proposals for Stages 1, 2, and 3; and the linked lists of Stage 0 proposals, Inactive proposals, and Finished proposals.
-- T.J. Crowder
Hi,
This already has a Stage 0 proposal here:
https://github.com/tc39/proposal-bind-operator.
You can find all proposals at https://github.com/tc39/proposals in
(currently) three categories: That page itself, which lists proposals for
Stages 1, 2, and 3; and the linked lists of Stage 0 proposals, Inactive
proposals, and Finished proposals.
-- T.J. Crowder
On Sun, Feb 4, 2018 at 4:32 PM, Ludwig GUERIN <ludwig.guerin.98 at gmx.fr>
wrote:
> Sometimes, you need to pass a callback as a parameter of a function.
>
> Sometimes, you would like to pass in a method as the said parameter but
> you may encounter the common issue that the this keyword is not bound to
> the correct context anymore ; therefore you need to bind the correct
> context.
>
>
>
> Let's says that you have :
>
> - a function `f` which receives a callback
> -
>
> and an object `obj` which has a method `method` which requires the `
> this` keyword to be bound to `obj` in order to work properly as
> intended.
>
>
>
> You will probably call `f` this way :
>
> `f(obj.method.bind(obj));`
>
>
>
> This is perfectly fine but sometimes can lead to a very large amount of
> extra "effort" for something that should not require that much "effort" and
> tends to take away a lot of space and clarity :`
>
> `f(obj.prop.method.bind(obj.prop));`
>
>
>
> My suggestion to solve this issue would be to use a new notation based
> around what C++ developers call the *scope resolution operator*, aka `::`.
>
> Here are details on how this should work :
>
> -
>
> `{object}` refers to an object (it can be either obj, or obj.method,
> or obj.prop, etc...)
> -
>
> `{method}` refers to one of `{object}`'s methods (if `{object}` is obj
> and we have `obj.method` then `{method}` would be `method`)
> -
>
> The "old-fashioned" way would look like `{object}.{method}.bind({
> object})`
> -
>
> With this suggestion, it would look like `{object}::{method}`
>
>
>
> One way to implement such a functionality would be to establish a function
> autoBindContext which would guarantee the following properties :
>
> -
>
> `{object}::{method}` <=> `autoBindContext({object}.{method}, {object})`
> -
>
> Given any function/method `{fn}` (either `f` or `obj.method`), `autoBindContext({fn},
> null) === {fn}`
> -
>
> `{object}::{method}` <=> `({object})::{method}`
> - const a = {object}::{method};
> const b = {object}::{method};
> a==b; //is true
> a===b; //is true
>
>
>
> Below is one implementation of autoBindContext :
>
> ```javascript
>
> const autoBindContext = (method, context=null) => {
> if(typeof method !== "function")
> throw new TypeError("Can only bind the context of a function/method");
>
> if(context === null)
> return method; //Do not bind if the context is null
>
> if(!(context instanceof Object))
> throw new TypeError("Can only bind a function's/method's context to an object");
>
> const self = autoBindContext;
> if(!self.cache.hasBinding(method, context))
> self.cache.addBinding(method, context);
>
> return self.cache.getBinding(method, context);
> }
>
> autoBindContext.cache = {
> /***********************************\
> binding: {context, method, bound}
> \***********************************/
> bindings: [],
> lookForBinding(method, context=null){
> return this.bindings.find(binding => {
> return binding.context === context
> && binding.method === method;
> });
> },
> hasBinding(method, context=null){
> return this.lookForBinding(method, context) !== undefined;
> },
> getBound(method, context=null){
> if(this.hasBinding(method, context))
> return this.lookForBinding(method, context).bound;
>
> return null;
> },
> getBinding(method, context=null){
> return this.getBound(method, context);
> },
> addBinding(method, context=null){
> if(!this.hasBinding(method, context)){
> this.bindings.push({
> context,
> method,
> bound: method.bind(context)
> });
> }
>
> return this;
> }
> };
>
> ```
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180204/a5251877/attachment.html>
Sometimes, you need to pass a callback as a parameter of a function.
Sometimes, you would like to pass in a method as the said parameter but you may encounter the common issue that the this keyword is not bound to the correct context anymore ; therefore you need to bind the correct context.
Let's says that you have :
fwhich receives a callbackobjwhich has a methodmethodwhich requires thethiskeyword to be bound toobjin order to work properly as intended.You will probably call
fthis way :f(obj.method.bind(obj));This is perfectly fine but sometimes can lead to a very large amount of extra "effort" for something that should not require that much "effort" and tends to take away a lot of space and clarity :
f(obj.prop.method.bind(obj.prop));My suggestion to solve this issue would be to use a new notation based around what C++ developers call the scope resolution operator, aka
::.Here are details on how this should work :
{object}refers to an object (it can be eitherobj, orobj.method, orobj.prop, etc...){method}refers to one of{object}'s methods (if{object}isobjand we haveobj.methodthen{method}would bemethod){object}.{method}.bind({object}){object}::{method}One way to implement such a functionality would be to establish a function
autoBindContextwhich would guarantee the following properties :{object}::{method}<=>autoBindContext({object}.{method}, {object}){fn}(eitherforobj.method),autoBindContext({fn}, null) === {fn}{object}::{method}<=>({object})::{method}const a = {object}::{method}; const b = {object}::{method}; a==b; //is true a===b; //is trueBelow is one implementation of
autoBindContext:const autoBindContext = (method, context=null) => { if(typeof method !== "function") throw new TypeError("Can only bind the context of a function/method"); if(context === null) return method; //Do not bind if the context is null if(!(context instanceof Object)) throw new TypeError("Can only bind a function's/method's context to an object"); const self = autoBindContext; if(!self.cache.hasBinding(method, context)) self.cache.addBinding(method, context); return self.cache.getBinding(method, context); } autoBindContext.cache = { /***********************************\ binding: {context, method, bound} \***********************************/ bindings: [], lookForBinding(method, context=null){ return this.bindings.find(binding => { return binding.context === context && binding.method === method; }); }, hasBinding(method, context=null){ return this.lookForBinding(method, context) !== undefined; }, getBound(method, context=null){ if(this.hasBinding(method, context)) return this.lookForBinding(method, context).bound; return null; }, getBinding(method, context=null){ return this.getBound(method, context); }, addBinding(method, context=null){ if(!this.hasBinding(method, context)){ this.bindings.push({ context, method, bound: method.bind(context) }); } return this; } };