Reputation: 3995
I am trying to work out how to test if a variable is an instance of a specific bound function. Consider the following example:
var func = function( arg ) {
// code here
}
myFunc = func.bind( null, 'val' );
if( myFunc == func ) {
console.log( true );
} else {
console.log( false );
}
Unfortunately this results in false. Is there some sort of way of testing the variable to find out what function it is bound to?
Upvotes: 1
Views: 1751
Reputation: 1566
You can use the instanceof
operator as long as your bound function is a constructable function and the variable you are testing is an instance of your constructable.
When using a bound function as the right-hand side of instanceof, instanceof would reach for the target function (which is stored internally in the bound function) and read its prototype instead.
var func = function( arg ) {
// code here
}
myFunc = func.bind( null, 'val' );
if( new func instanceof myFunc ) {
console.log( true );
} else {
console.log( false );
}
You simply have to write func
so that it doesn't do anything unwanted when creating a new instance of it. For example if func doesn't need to construct:
var func = function( arg ) {
if (this instanceof func) return;// do nothing
// code here
}
Upvotes: 0
Reputation: 1772
Bind prepend "bound " before the source function's name.
If you can give a explicite name to the source function then you can do :
var func = function func( arg ) {
// code here
}
var myFunc = func.bind( null, 'val' );
if( myFunc.name.match(/^(bound\ )*(.*)$/i)[2] === func.name ){
console.log(true);
}
Upvotes: 1
Reputation: 3995
Thanks for your input @jfriend00 and @PaulS. I am using a function that automatically adds an unbound property to the bound function. Here is a refined version of what I wrote. Let me know what you think.
// My function
var myFunc = function() {
return 'This is my function';
};
// Function I'm wrapping my function in
var wrapper = function( fn ) {
var result;
if( fn ) {
result = fn.apply( null, arguments );
}
// Any additional logic I want to run after my function
console.log( 'Ran wrapper logic' );
return result;
};
// Modified binder method
var binder = function( fn, ths, args ) {
args = [].concat( ths, args );
var bound = fn.bind.apply( fn, args );
bound.unbound = fn;
return bound;
};
// Bind a wrapped version of my function
myFunc = binder( wrapper, null, myFunc );
// I can test if my function has ben wrapped
console.log( myFunc.unbound == wrapper );
// And I can run a wrapped version of my function
console.log( myFunc() );
Upvotes: 0
Reputation: 707716
No, there is not a way to do this. .bind()
returns a new function that internally calls the original one. There is no interface on that new function to retrieve the original one.
Per the ECMAScript specification 15.3.4.5, the returned "bound" function will have internal properties for [[TargetFunction]]
, [[BoundThis]]
and [[BoundArgs]]
, but those properties are not public.
If you tell us what higher level problem you're trying to solve, we might be able to come up with a different type of solution.
If you yourself control the .bind()
operation, you could put the original function on the bound function as a property and you could test that property:
var func = function( arg ) {
// code here
}
myFunc = func.bind( null, 'val' );
myFunc.origFn = func;
if( myFunc === func || myFunc.origFn === func) {
console.log( true );
} else {
console.log( false );
}
Demo: http://jsfiddle.net/jfriend00/e2gq6n8y/
You could even make your own .bind()
replacement that did this automatically.
function bind2(fn) {
// make copy of args and remove the fn argument
var args = Array.prototype.slice.call(arguments, 1);
var b = fn.bind.apply(fn, args);
b.origFn = fn;
return b;
}
Upvotes: 7
Reputation: 66364
You can't do this directly because functions, just like Objects, have their equality tested by their reference which no longer matches, §11.9.3, point 1. f. or §11.9.6, point 7.
However, you could create some custom properties to test for, e.g.
function myBind(fn) { // takes 2+ args, the fn to bind, the new this, any other args
var bind = Function.prototype.bind,
bound = bind.call.apply(bind, arguments);
bound.unbound = fn;
return bound;
}
and then examle usage
function foo(bar) {
console.log(this, bar);
}
// binding
var fizz = myBind(foo, {buzz:0}, 'baz');
fizz(); // logs {buzz: 0} "baz"
// testing
fizz.unbound === foo; // true
If you want to test in both directions, then you will need to OR them together, and perhaps even consider looping over these properties if you will be binding already bound functions
fizz.unbound === foo || fizz === foo.unbound; // true
Please also consider that the whole chain of unbound versions of the function will not be released from memory as long as a bound version exists, whereas some browsers would have been able to free this memory, depending on their implementation of bind
Upvotes: 2