2

Is possible to get the original function "behind" a function that is a result of .bind()? I want to get the toString() of it.

function foo() {
    return 'bar';
}

let baz = foo.bind();

console.log(baz.toString()); //-> function foo() { return 'bar'; } and not -> function () { [native code] }
André Vinícius
  • 411
  • 4
  • 12
  • I think OP means the original unbound context of `this`? – Sterling Archer Nov 29 '17 at 15:42
  • Perhaps if you provide an [mcve] of what you're trying to achieve we must understand your question better. – Andy Nov 29 '17 at 15:45
  • 1
    @ste2425 `(function foo(){ console.log('foo') }).bind({}).toString()` gives `function () { [native code] }` in chrome. So the question has merit, if I'm understanding it correctly. – Jared Smith Nov 29 '17 at 15:49
  • 1
    @JaredSmith Thanks for the heads up, [Heres](https://tc39.github.io/ecma262/#sec-function.prototype.tostring) the spec that defines the behavior for reference. Didn't realize a bound function is considered an exotic object, makes sense though. – ste2425 Nov 29 '17 at 15:56
  • I guess the OP somehow want to access the BoundTargetFunction mentioned here but it is an internal property. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind – Henry Liu Nov 29 '17 at 16:01

2 Answers2

3

There's not a built in link to get from baz to foo, but you could add one:

function foo() {
    return 'bar';
}

let baz = foo.bind(this);
baz.original = foo;

console.log(baz.original.toString()); 

If you wanted this to happen automatically whenever someone binds a function, you could override Function.prototype.bind. Not something i would recommend, but it would look something like this:

// Using an IIFE to isolate realBind from eveyone else's scope
(function () {
  const realBind = Function.prototype.bind;
  Function.prototype.bind = function () {
    const result = realBind.apply(this, arguments);
    result.original = this;
    return result;
  }
}());

function foo() {
    return 'bar';
}

let baz = foo.bind(this);
console.log(baz.original.toString()); 
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
1

So, after some digging around...

It does not appear that there is any way in firefox to make this work without overriding built in methods.

However in chrome the following does work:

function foo() { console.log('yo'); };
console.log(foo.bind({}).toString()); // function () { [native code] }
console.log(foo.bind({})); // f foo () { console.log('yo') }

So while there is no way to get the original back out with a call .toString, logging the function object directly to the console in chrome will yield a representation with the body of the original function.

Here is a link to the relevant section of the spec for Function.prototype.toString courtesy of ste2425.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
  • 1
    Not that it matters, but just as a point of interest this doesn't work in IE11 either. Both `console.log` calls yield the same result (the first one). – freginold Nov 29 '17 at 16:03
  • Also, without programmatic access to the value it's probably somewhat pointless. – deceze Nov 29 '17 at 16:04
  • @deceze agreed, but it's the best I could come up with without overriding the builtin methods of the function prototype. – Jared Smith Nov 29 '17 at 16:05
  • You must be able to do this just with the product of bind without know what function is behind. Sure if it's possible... – André Vinícius Nov 29 '17 at 17:06
  • 1
    @AndréVinícius again, you can simply log the function object to the console. For instance, consider file a.js that has `function foo() {}; const bar = foo.bind({}); export default bar;` and file b.js that has `import boundFoo from './a.js'; console.log(boundFoo);` you will see the body of `foo` rather than `function () { [ native code ] }`. The problem is as deceze pointed out that you have no *programmatic* access to the string representation, you can only see it in the console. – Jared Smith Nov 29 '17 at 17:42
  • @AndréVinícius Looking into it more its not possible because of how the spec defines the bound function. The original function is placed in an internal slot `[[BoundTargetFunction]]`. These are not available in user code but implementation specific (IE JavaScript engine). Some API's provide public getters to these, such as `new String('lol').toString()` which will return the internal slot holding the string value. Interestingly people have written proposals for private properties using dynamic internal slots. – ste2425 Dec 01 '17 at 08:48