bind
method creates a new function that when called has its this
keyword set to the provided value.
var obj = {
a: 0,
b() {
console.log(this.a);
}
}
obj.b() // -> 0
var functionBound = obj.b.bind(obj)
functionBound() // -> 0
functionBound.bind(null)() // -> 0 AND I expect an error here
Clearly, I cannot rebind a function has already been rebound. However, I could not find any documentation on this behavior.
Quote from "Bind more arguments of an already bound function in Javascript"
Once you bound an object to a function with bind, you cannot override it. It's clearly written in the specs, as you can see in MDN documentation:
The bind() function creates a new function (a bound function) with the same function body (internal call property in ECMAScript 5 terms) as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(), which cannot be overridden.
I could not find these in MDN documentation. I did an exact full-text search on the quote above on Google and seems the SO answer above is the only source for this behavior. I also try to find an answer in the language spec with no luck.
My question is do you know this behavior and where can I find any official documentation on these?
This may not directly answer the question about getting a officially documented specification validating this behavior, but we can base our conclusions on the source code provided in MDN, specifically in the documentation for Function.prototype.bind(), under section Polyfill, where they provide an example of how a polyfill bind
function would look like.
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
}
We can see that the oThis
parameter is used in the closure fBound
which is the one ultimately returned by the bind
function.
This means that when you invoke the bind
function, you get a closure function in return which, when invoked, accesses the oThis
free variable provided as parameter in the original invocation of bind
.
As such, it doesn't matter how many more times you rebind the bound fBound
function, this function is already bound forever to the original context oThis
within its closure.
The MDN documentation also points to Raynos bind implementation for further reference, which seems to correspond to this example as well.
The problem is that Function.prototype.bind returns a NEW function instead of the same. Calling a bound function with a different this-argument has no effect, because the bound function already knows which value to use as the this-argument.
You could use this for binding your functions:
Function.boundOriginProp = Symbol()
Function.prototype.bindDynamic = thisArg => {
let origin = this[Function.bindOriginProp] || this
let bound = (...args) => origin.call(thisArg, ...args)
bound[Function.bindOriginProp] = origin
return bound
}
So you can rebind functions that have already been bound like this:
let obj1 = { value: 1 }
let obj2 = { value: 2 }
function example() {
console.log(this.value)
}
let fn1 = example.bindDynamic(obj1)
fn1() // -> 1
let fn2 = fn1.bindDynamic(obj2)
fn2() // -> 2
let fn3 = fn1.bindDynamic(null)
fn3() // -> undefined
I hope this can help you ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With