51
var test = {
    demo: function(){
      //get the caller context here
    }
}
//when this gets called, the caller context should be window.
test.demo();

I tried arguments.callee and arguments.callee.caller,and no luck...

new_perl
  • 7,345
  • 11
  • 42
  • 72
  • What do you mean by "caller context"? Perhaps you mean the value of its *this* keyword? – RobG Mar 13 '12 at 06:01
  • @RobG,in my example,it should be `window`,effectually `this` keyword at calling site. – new_perl Mar 13 '12 at 06:02
  • is there any reason you can't just pass it in? `test.demo(this)`? – david Mar 13 '12 at 06:09
  • 1
    @cycaHuH—That is passing a *this* value to the function, you can set it to anything from the call (which is one reason why it is so misleading to call *this* "context"). Since the value is supposed to be the caller's *this*, then it should be `test.demo.call(this)`, but I suspect the OP doesn't want to trash the function's default *this*, which would be `demo`. – RobG Mar 13 '12 at 06:14

4 Answers4

53

Since this keyword referes to ThisBinding in a LexicalEnvironment, and javascript (or ECMAScript) doesn't allow programmatic access to LexicalEnvironment (in fact, no programmatic access to the whole Execution Context), so it is impossible to get the context of caller.

Also, when you try test.demo() in a global context, there should be no caller at all, neither an attached context to the caller, this is just a Global Code, not a calling context.

otakustay
  • 11,817
  • 4
  • 39
  • 43
  • 1
    @otakustay—You are aboslutely correct about not being able to reference variables as properties of other variable objects. But as a special case, global variables are made properties of the global object so you can in fact access variables in the calling context **if** it's global. You could test for the (deprecated, non–standard) `arguments.callee.caller` property and if it's `null` assume the call is from global code, then hope you're not in ES5 strict mode, get a reference to the global object and go from there. – RobG Mar 13 '12 at 06:28
  • 1
    This is where you run into problems with Node.JS and modules. – Qix - MONICA WAS MISTREATED Feb 06 '14 at 08:39
9

By context, I assume you mean this? That depends on how the function is invoked, not from where it is invoked.

For example (using a Webkit console):

var test = {
    demo: function() {
        console.log(this);
    }
}
test.demo();    // logs the "test" object
var test2 = test.demo;
test2();        // logs "DOMWindow"
test.demo.apply("Cheese"); // logs "String"

Incidentally, arguments.caller is deprecated.

Seth
  • 45,033
  • 10
  • 85
  • 120
5

The value of a function's this keyword is set by the call, it isn't "context". Functions have an execution context, which includes its this value. It is not defined by this.

In any case, since all functions have a this variable that is a property of its variable object, you can't reference any other this keyword in scope unless it's passed to the function. You can't directly access the variable object; you are dependent on variable resolution on the scope chain so this will always be the current execution context's this.

isherwood
  • 58,414
  • 16
  • 114
  • 157
RobG
  • 142,382
  • 31
  • 172
  • 209
0

Strange how we are talking about this except for
'Qix - MONICA WAS MISTREATED''s comment. Either you are able to capture

  1. window,
  2. worker self,
  3. v8::Isolate v8::context is extended in fetch for cloudflare workers (or use this of the class), or
  4. rename some other function-method's scope-this-context outside, so

this hypothetical situation has no use case.

var test = {
    demo: function(){
      //get the caller context here
    }
}

test.demo();

For closure, one could have a dynamically named function factory for some reason, while maintaining its context like so:

function body () {}
var test = {
  demo: {
    [name]: function () {return body.apply(body, arguments);} 
       }[name];

Without for loop, thisArg argument would be {demo:fn()}

var test = {demo:{}}
const createNamedFunc = (body) => {
  test.demo = return {
    [name]: function () {
      return body.apply(body, arguments);
         } } [name];
}
createNamedFunc(function body (){})

I gather this 'functional-method-parameter-object' is

  1. the deepest-functional-method-child of the object-declarations
  2. of the global scope receiver[ object]
  3. passing it on, until the next non-object nor -data-type returnable type definition or instantiation, not necessarily declaration but always implement/extension scope interface.