Replicating arguments.callee in strict mode

2019-02-12 17:01发布

问题:

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?

回答1:

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?

No. You have to give the function a name. My mistake, I thought of a way, see the final code block below. I don't like it, but there we are. :-)

Note that the way you're giving the function a name here:

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
   }
})

...uses a named function expression. These are notoriously unreliable (link, link) across implementations (they shouldn't be, but are), most notably in your example above, IE8 and earlier will create two completely separate function objects, assigning one of them to the generateScale property and referring to a different function object within the function as GS.

It's easy to fix, though:

UsageGraph = Graph.extend(function(){
   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
   }

   return {generateScale: GS};
}())

Or if you really don't want the function to have a name (I prefer that they have names, helps my tools help me, but hey), you can use a local within that closure:

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};
}())

Now you have an anonymous function, but can refer to it as GS from within it. Again, I wouldn't recommend it, because then you can't see the function name in call stacks and such, but you did say without giving the function a name, so...



回答2:

Yes, but no... I'm not sure if this is the same manner of "naming" that you speak of:

var foo = function bob() {
    // call bob();
}

// bob is undeclared; here it's foo!

http://jsfiddle.net/4y8pY/