2

I have a function foo that calls function bar. foo is bound to an element test.

When being called, bar stores its caller function (foo) inside the set s. When I now run the function foo inside s, strangely this is now set to Window. But I did bind the function, so what am I getting wrong?

var s = new Set();

function bar() {
  s.add(bar.caller)
}

var test = document.getElementById('test');
test.foo = (function() {
  bar();
  console.log(this);
}).bind(test);

test.foo(); // output: test div
s.forEach(fn => fn()); // output: Window object
<div id="test"></div>
adiga
  • 28,937
  • 7
  • 45
  • 66
DonFuchs
  • 123
  • 6
  • Does this answer your question? [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Sebastian Kaczmarek Nov 13 '19 at 07:38
  • "This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future." ~ [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller) I can't tell you how it works cause it is implementation specific. – Jonas Wilms Nov 13 '19 at 07:45
  • @JonasWilms Fair enough, but I would reckon it has nothing to do with `caller` as it seems to be poiting to the correct function. I thought it had something to do with how I then execute this function. – DonFuchs Nov 13 '19 at 08:01
  • 1
    @SebastianKaczmarek Thanks, but it doesn't – DonFuchs Nov 13 '19 at 08:03
  • @DonFuchs I suggest you analyze this answer: https://stackoverflow.com/a/3127440/7080548, especially the *Examples* part - 3rd example is pretty similar to what your code does – Sebastian Kaczmarek Nov 13 '19 at 08:11
  • [How do I create a runnable stack snippet?](https://meta.stackoverflow.com/questions/358992) – adiga Nov 13 '19 at 08:18

1 Answers1

2

A bound function basically calls the function it is binding over¹ with the bounded this, so the callstack of your code looks like

 [Bound] test.foo -> test.foo -> bar

So from bar's point of view, it was called from test.foo not from the bound function.²


¹ as stated in the spec:

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


² wether function.caller returns the upmost callstack entry is not quite clear, as it is not specified. That's an assumption.

Jonas Wilms
  • 106,571
  • 13
  • 98
  • 120
  • oddly enough logging ```bar.caller.toString()``` does give the source code of ```test.foo```, but inside of ```bar```, checking for strict equality (```bar.caller === test.foo```) returns ```false```. Setting ```test.foo.dummy=2``` gives ```undefined``` as well for ```console.log(bar.caller.dummy)``` – grodzi Nov 13 '19 at 08:33
  • 2
    @user753642 `bar.caller === test.foo` returning `false` actually does comply with JonasWilms answer, because `test.foo` is the bound `foo` whereas `bar.caller` the unbound one – DonFuchs Nov 13 '19 at 08:44
  • 1
    @user753642 And as for setting `test.foo.dummy = 2` and reading it from `bar`, this is not working as you are again acting on the bound `foo`; if you set `foo.dummy` before binding, you can access `dummy` from `bar` too – DonFuchs Nov 13 '19 at 08:46
  • 1
    @JonasWilms That makes sense to me, great answer – DonFuchs Nov 13 '19 at 08:48
  • yes I overlooked the part : it was called from test.foo __not from the bound function__. I also checked ```foo.dummy``` which is indeed accessible from ```bar``` as "predicted" – grodzi Nov 13 '19 at 08:49