Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reference a function from within its own implementation?

Tags:

javascript

I'm developing a javascript application that consists of many objects and functions (object methods). I want to be able to log many events in the life cycle of the application. My problem is that inside the logger I want to know which function invoked the log entry, so I can save that data along with the log message. This means that every function needs to somehow be able to reference itself, so I can pass that reference to the logger. I'm using javascript strict mode, so using arguments.callee inside the function is not allowed.

Here's a very simplified code sample you can run. I'm just using here alert instead of my logger for simplicity.

(function(){
"use strict";

window.myObject = {
    id : 'myObject',
    myFunc : function(){
        alert(this.id); // myObject
        alert(this.myFunc.id); // myFunc - I don't want to do this. I want something generic for all functions under any object
        alert('???') // myFunc
        alert(arguments.callee.id); // Will throw an error because arguments.callee in not allowed in strict mode
    }
}
myObject.myFunc.id = 'myFunc';

myObject.myFunc();
})();
  1. In the first alert - this related to myObject and not to myFunc
  2. In the second I alert - I referenced the function by its name, which I don't want to do, as I'm looking for a generic way to reference a function from within its own implementation.
  3. The third alert - open for your ideas.
  4. The fourth alert - would have worked if I didn't "use stict";. I want to keep strict mode since it provides better performance, and constitutes good coding practice.

Any input will be appreciated.

If you're not familiar with "strict mode", this is a good place read about it: JavaScript Strict Mode

like image 249
Orr Siloni Avatar asked Oct 09 '22 05:10

Orr Siloni


1 Answers

Here's a very hacky way of doing it:

(function(){
    "use strict";
    window.myObject = {
        id: 'myObject',
        myFunc: function () {
            // need this if to circumvent 'use strict' since funcId doesn't exist yet
            if (typeof funcId != 'undefined') 
                alert(funcId);
        },
        myFunc2: function () {
            // need this if to circumvent 'use strict' since funcId doesn't exist yet
            if (typeof funcId != 'undefined') 
                alert(funcId);
        }
    }
    // We're going to programatically find the name of each function and 'inject' that name
    // as the variable 'funcId' into each function by re-writing that function in a wrapper
    for (var i in window.myObject) {
        var func = window.myObject[i];
        if (typeof func === 'function') {
            window.myObject[i] = Function('var funcId = "' + i + '"; return (' + window.myObject[i] + ')()');
        }
    }

    window.myObject.myFunc();
    window.myObject.myFunc2();
})();

Essentially, we are circumventing the 'use strict' declaration by recompiling each function from a string after we've found out that function's name. To do this, we create a wrapper around each function that declares a string variable 'funcId' equal to our target function's name, so that the variable is now exposed to the function within through closure.

Eh, not the best way to do things, but it works. Alternatively, you can simply call a non-strict function from within:

(function(){
    "use strict";

    window.myObject = {
        id: 'myObject',
        myFunc: function () {
            alert(getFuncName())
        },
        myFunc2: function () {
            alert(getFuncName());
        }
    }
})();

// non-strict function here
function getFuncName(){
    return arguments.callee.caller.id; // Just fyi, IE doesn't have id var I think...so you gotta parse toString or something
}

Hope that helps.

like image 95
Skyd Avatar answered Oct 13 '22 09:10

Skyd