Suggestion : "automatic" context binding
# T.J. Crowder (7 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 :
f
which receives a callbackobj
which has a methodmethod
which requires thethis
keyword to be bound toobj
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 eitherobj
, orobj.method
, orobj.prop
, etc...){method}
refers to one of{object}
's methods (if{object}
isobj
and we haveobj.method
then{method}
would bemethod
){object}.{method}.bind({object})
{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})
{fn}
(eitherf
orobj.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
: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; } };