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 eitherobj
, orobj.method
, orobj.prop
, etc...) -
`{method}`
refers to one of`{object}`
's methods (if`{object}`
isobj
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@mozilla.org https://mail.mozilla.org/listinfo/es-discuss