Search code examples
javascriptfunctionscopestrict

Replicating arguments.callee in strict mode


I'm working in strict mode for the first time and, what-d'ya-know, it's also the first time in ages being able to use a non strict mode property would be useful. My question here outlines the exact problem I'm having, but the solution I've worked out could be adapted to something a lot more scaleable if I still had access to arguments.callee.

Without naming the function is there any way in strict mode that I can get a reference to the function whose scope I'm currently within?


Solution

  • Without naming the function is there any way in strict mode that I can get a reference to the function whose scope I'm currently within?

    In 2012 when this answer was originally written, there were implementation bugs with the named function expressions you were using in your linked solution. There aren't now, it's been years since browsers with those bugs were still in significant circulation. So here in a (very) post-IE8 world, your named function expression approach is just fine:

    UsageGraph = Graph.extend({
       generateScale: function GS() {
           var parentMethod = this.constructor._super.generateScale;
           if(parentMethod === GS) {
               parentMethod = this.constructor._super.constructor._super.generateScale;
           }
           parentMethod.call(this); // run the parent's method
           //do additional stuff
       }
    });
    

    But the question asks if you can avoid having a name. In 2012, my solution if you really didn't want the function to have a name was to assign an anonymous function to a variable:

    UsageGraph = Graph.extend(function(){
       var GS = function() {
           var parentMethod = this.constructor._super.generateScale;
           if(parentMethod === GS) {
               parentMethod = this.constructor._super.constructor._super.generateScale;
           }
           parentMethod.call(this); // run the parent's method
           //do additional stuff
       };
    
       return {generateScale: GS};
    }());
    

    But that doesn't work anymore; since ES2015, even that function has a name, inferred from the name of the variable it's assigned to:

    var GS = function() { };
    console.log(GS.name); // "GS"

    If you really don't want it to have a name, it's possible to avoid it, but you have to make an effort to defeat the automatic naming defined by the specification, for instance by making the function the return value of another function:

    var GS = (() => function() { })();
    console.log(GS.name); // ""

    So if avoiding the name is important, you'd do something like this:

    UsageGraph = Graph.extend(function(){
       const generateScale = (() => function() {
           let parentMethod = this.constructor._super.generateScale;
           if(parentMethod === generateScale) {
               parentMethod = this.constructor._super.constructor._super.generateScale;
           }
           parentMethod.call(this); // run the parent's method
           //do additional stuff
       })();
    
       return {generateScale};
    }());