22

Strict and non-strict code can be mixed. But you can't use caller even if the call to it is not in strict code. Does anybody know any workaround?

I tried this:

(function strict(){
    "use strict";
    nonStrict();//ok
    nonStrictCaller();//error :(
})();

function nonStrict(){
    return 011;//Octal literals are not allowed in strict mode
}

function nonStrictCaller(){
    return nonStrictCaller.caller;
}
Kara
  • 6,115
  • 16
  • 50
  • 57
Quadroid
  • 825
  • 2
  • 9
  • 15
  • 1
    You can pass `this` to the function, can't you? – gdoron Mar 19 '12 at 21:06
  • i think you may wanna look here, especially in the comments http://stackoverflow.com/a/280396/575527 – Joseph Mar 19 '12 at 21:20
  • The workaround is to make your code compliant with strict mode. That's sort of the point of strict mode; *it's strict*. In your case, it would mean making the caller accessible by some other means, like passing it by name as an argument. –  Mar 19 '12 at 21:31
  • @amnotiam I'm writing framework, and I need caller to implement private & protected properties with access from methods in prototype. – Quadroid Mar 19 '12 at 23:34
  • 2
    If that's your approach, then your framework won't work in strict mode environments. Are you using the caller property to verify that some method was called from a prototyped method? Something similar? –  Mar 20 '12 at 00:48
  • If `"use strict"` breaks code that is not within it's scope, what's the point of `"use strict"` having a scope then? – AndreKR Apr 06 '14 at 04:50

1 Answers1

12

Here's an evil hack that only works in V8. The 140 bytes version:

function x(a,b,c){function d(e,f){d=f}c=(b=Error)[a='prepareStackTrace'];b.captureStackTrace(b[a]=d,x);d.stack;b[a]=c;return d}

And the less cryptic version

if ('captureStackTrace' in Error) {
  void function(){
    function prepare(e, callsites){
      return callsites;
    }

    function stack(f){
      var e = {};
      var oldPrepare = Error.prepareStackTrace;
      Error.prepareStackTrace = prepare;
      Error.captureStackTrace(e, f || stack.caller);
      e = e.stack;
      Error.prepareStackTrace = oldPrepare;
      return e;
    }

    function lastReceiver(){
      return stack(lastReceiver)[2].receiver;
    }

    var CallSite = stack()[0].constructor;
    var callsiteMethods = {};

    Object.getOwnPropertyNames(CallSite.prototype).forEach(function(key){
      if (/^is|^get/.test(key)) {
        callsiteMethods[key.replace(/^is|^get/, '')] = CallSite.prototype[key];
      }
      callsiteMethods.location = CallSite.prototype.toString;
    });

    CallSite.prototype.resolve = function resolve(){
      for (var k in callsiteMethods)
        this[k] = callsiteMethods[k].call(this);
    }

  }();
}
vsync
  • 118,978
  • 58
  • 307
  • 400