Reputation: 263
I have a function that is already bound by using Function.prototype.bind method. Somehow, I want to override the this parameter of the bound function. But it does not work. Check the description in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind , it says that 'this' can not be override. Is there any workaround/ solution to override 'this' of bind function? My test code:
function testF() {console.log(this)}
var test = testF.bind('abc');
test = test.bind('xyz');
test() // print 'abc' instead of 'xyz'. I'm expecting to print 'xyz'
Upvotes: 4
Views: 2288
Reputation: 432
Answer for general development:
//if the function is declared like this
let call=function(){console.log(this);}
// then you can pull the function out of bind through the prototype.
call.bind({hello:'my firend'});
call();// print {hello:'my firend'}
call= Object.getPrototypeOf(new call()).constructor;
call(); print {window}
call=call.bind({bay:'my darling'});
call(); print {bay:'my darling'}
Disadvantage: you need to call the constructor, as a result of which the body of the function is called and thus may have side effects from the call. For example, a call is calculated 1 time and subsequently the variables in the context of the function but outside of it will be changed or deleted. Or throw an error.
If you have access to the native function, then you need to do this:
function call(){
console.log(this);
}
call=Object.assign(call.bind({hello:'my friend'}),{owner:call});
let otherCall=Object.assign(call.bind({hello:'my friend'}),{owner:call.owner});
otherCall();
Upvotes: 0
Reputation: 7181
I'm going to hazard that no there is not.
The entire point of bind is to force the bound function to always execute with a given context. A rough idea of what bind does is:
function simpleBind(fn, context) {
return function() {
return fn.apply(context, arguments);
};
}
So you can clearly see here -- a new function is actually being returned here and so altering it's context has absolutely no effect on the wrapped (bound) function because it's using values from the enclosing function call.
My best guess at why you're looking to do something like this it hack something in place instead refactoring which is (almost always) the better approach. While I realize it may not be "in a budget" you're not really given a lot of options here. It's best to rethink your approach so you don't need to do these kinds of ugly hacks.
** This is a simplistic implementation just used to demonstrate the main point
edit
Taking some inspiration from @djechlin's comments I was going to demonstrate a way to "abuse" this simpleBind
implementation by using reference type (I quote abuse, because this isn't really doing anything you weren't already allowed to do). In your case, where you're binding a string (assuming you have some control over bound values) you can do something simple like:
var context = {string: "abc"},
fn = function() { console.log(this.string); },
bound = fn.bind(context);
bound(); // logs 'abc'
context.string = "xyz";
bound(); // logs 'xyz'
This would only be useful if you could alter the values being bound to a function and uses the concept that they are references and not copies which is standard JS behavior.
Upvotes: 3
Reputation: 816730
Is there any workaround/ solution to override 'this' of bind function?
No. As you can see in the spec, the .bind
method returns a new bound function:
[...]
4. Let F be BoundFunctionCreate(Target, thisArg, args).
[...]
16. Return F.
A bound function is described as:
A bound function is an exotic object that wraps another function object. A bound function is callable (it has a
[[Call]]
internal method and may have a[[Construct]]
internal method). Calling a bound function generally results in a call of its wrapped function.
A bound function also has an internal [[BoundThis]]
property:
The value that is always passed as the
this
value when calling the wrapped function.
(emphasis mine)
Looking at the internal [[Call]]
method confirms that too:
9.4.1.1 [[Call]] ( thisArgument, argumentsList)
When the
[[Call]]
internal method of an exotic bound function object, F, which was created using the bind function, is called with parameters thisArgument and argumentsList, a List of ECMAScript language values, the following steps are taken:
- Let target be the value of F’s
[[BoundTargetFunction]]
internal slot.- Let boundThis be the value of F’s
[[BoundThis]]
internal slot.- Let boundArgs be the value of F’s
[[BoundArguments]]
internal slot.- Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list argumentsList in the same order.
- Return Call(target, boundThis, args).
As you can see, thisArgument
is completely ignored, only the value of [[BoundThis]]
is used. There is no way to change [[BoundThis]]
after it was set.
Upvotes: 12