29

Is there a way to get all methods (private, privileged, or public) of a javascript object from within? Here's the sample object:

var Test = function() {
// private methods
    function testOne() {}
    function testTwo() {}
    function testThree() {}
// public methods
    function getMethods() {
      for (i in this) {
        alert(i); // shows getMethods, but not private methods
      }
    }
    return { getMethods : getMethods }
}();

// should return ['testOne', 'testTwo', 'testThree', 'getMethods']
Test.getMethods();

The current issue is the code in getMethods(), the simplified example will return just the public methods, but not to private ones.

edit: my test code may (or may not) be overcomplicating what i'm hoping to get at. given the following:

function myFunction() {
  var test1 = 1;
  var test2 = 2;
  var test3 = 3;
} 

is there a way to find out what variables exist in myFunction() from within myFunction(). the pseudo-code would look like this:

function myFunction() {
  var test1 = 1;
  var test2 = 2;
  var test3 = 3;

  alert(current.properties); // would be nice to get ['test1', 'test2', 'test3']
}
Owen
  • 82,995
  • 21
  • 120
  • 115

7 Answers7

29

The technical reason why those methods are hidden is twofold.

First, when you execute a method on the Test object, "this" will be the untyped object returned at the end of the anonymous function that contains the public methods per the Module Pattern.

Second, the methods testOne, testTwo, and testThree aren't attached to a specific object, and exist only in the context of the anonymous function. You could attach the methods to an internal object and then expose them through a public method, but it wouldn't be quite as clean as the original pattern and it won't help if you're getting this code from a third party.

The result would look something like this:

var Test = function() {
    var private = {
        testOne : function () {},
        testTwo : function () {},
        testThree : function () {}
    };

    function getMethods() {
        for (i in this) {
            alert(i); // shows getMethods, but not private methods
        }
        for (i in private) {
            alert(i); // private methods
        }
    }
    return { getMethods : getMethods }
}();

// will return ['getMethods', 'testOne', 'testTwo', 'testThree']
Test.getMethods();

edit:

Unfortunately, no. The set of local variables aren't accessible via a single, automatic keyword.

If you remove the "var" keyword they would be attached to the global context (usually the window object), but that's the only behavior that I know of that is similar to what you're describing. There would be a lot of other properties and methods on that object if you did that, though.

Simon Featherstone
  • 1,716
  • 23
  • 40
Kevin Gorski
  • 3,745
  • 1
  • 22
  • 16
  • 1
    ya, that's what i was afraid about. i suppose the options are the structure you posted (ugh messsy), or just making the methods you want available "public". oh well :) – Owen Nov 09 '08 at 01:44
5

From http://netjs.codeplex.com/SourceControl/changeset/view/91169#1773642

//Reflection

~function (extern) {

var Reflection = this.Reflection = (function () { return Reflection; });

Reflection.prototype = Reflection;

Reflection.constructor = Reflection;

Reflection.getArguments = function (func) {
    var symbols = func.toString(),
        start, end, register;
    start = symbols.indexOf('function');
    if (start !== 0 && start !== 1) return undefined;
    start = symbols.indexOf('(', start);
    end = symbols.indexOf(')', start);
    var args = [];
    symbols.substr(start + 1, end - start - 1).split(',').forEach(function (argument) {
        args.push(argument);
    });
    return args;
};

extern.Reflection = extern.reflection = Reflection;

Function.prototype.getArguments = function () { return Reflection.getArguments(this); }

Function.prototype.getExpectedReturnType = function () { /*ToDo*/ }

} (this);
Jay
  • 3,276
  • 1
  • 28
  • 38
2

Javascript doesn't really have the notion of private anything. Because of that, javascript doesn't have a reflection API as such. The technique you're using doesn't so much make them private as render them inaccessible; they're hidden, not private. I think you could manage something by putting those methods somewhere manually.

sblundy
  • 60,628
  • 22
  • 121
  • 123
  • 9
    B doesn't follow from A. Languages can have a reflection API with or without data privacy. (The variables he has aren't even "hidden" or "private"; they're just locals.) Python doesn't have data privacy, yet it supports powerful reflection. – Glenn Maynard Dec 20 '10 at 04:31
  • 1
    - 1. The answer is misleading. See Glenn's comment "B doesn't follow from A. Languages can have a reflection API with or without data privacy" for more details. – andy Jun 21 '11 at 02:27
  • 1
    Javascript may not specifically use "private" identifiers like Java does, but it most certainly does have the notion of private variables and methods. Anything declared like "var a = 1" are implicitly private within a function since they cannot be accessed from outside. – JD Smith Jun 11 '12 at 18:54
  • 1
    Aye, no private/protected/public in Javascript because there's no inheritance per se. If we assert that we may implement private & protected by-convention, that will help. Common conventions are to use prepended underscores: Protected as: "_func()" and Private: "__func()". – will Sep 29 '12 at 16:39
  • @JD Smith ... Sorry to respond, I tend to let these thing lie. Unfortunately your not missed a very very HUGE thing about Algol based languages (such as C, C++, Pascal, Java, et al). Something: "var a = 1" is limited scope to the enclosing block. That's going to be lexical scope (nominally); in real Algol derivatives we have call scope, or name scope too. Alas (lost) in modern times ... – will Sep 29 '12 at 16:49
  • @JDSmith, Matter of semantics. Those are called **scoped** variables, not **private** members. – Pacerier Feb 22 '17 at 13:43
  • Thanks guys, I was a bit loose with my definition of "private". The computer science tips are much appreciated! – JD Smith Feb 28 '17 at 05:53
1

With a little change to the way the function is defined you can achieve what you want. Wrap the actual implementation of the function in an object literal it would then look like this:

(function() {
    var obj = {
    // private methods
    testOne: function () {},
    testTwo : function () {},
    testThree: function () {},
    // public methods
    getMethods : function () {
      for (i in this) {
        alert(i); // shows getMethods, but not private methods
      }
    }
    };
    return { getMethods : function(){return obj.getMethods();} }
})();
Rune FS
  • 21,497
  • 7
  • 62
  • 96
1

Part of the issue with your test code is that Test is the object created by your return statement: "{ getMethods : getMethods }" It has no testOne, testTwo, or testThree methods; instead, those are only available within the same namespace as the original getMethods function.

eswald
  • 8,368
  • 4
  • 28
  • 28
  • right, so i'm looking for a way to access that namespace within getMethods(). essentially, i was hoping i missed some theoretical reference (like this in other languages) – Owen Nov 09 '08 at 00:07
1

you can use var that = this; trick:

var Test = function() {
    var that = this;
    function testOne() {}
    function testTwo() {}
    function testThree() {}
    function getMethods() {
      for (i in that) {
        alert(i);
      }
    }
    return { getMethods : getMethods }
}();
GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
small_jam
  • 637
  • 2
  • 7
  • 7
0

If you call getMethods() like that, isn't it static? Surely you'd need to properly init the class for this to work as expected?

var t = new Test();
t.getMethods();

If that doesn't work, please take a look at the JS Serializer. I used it a while back for some debug and I think it worked for private vars.

Oli
  • 235,628
  • 64
  • 220
  • 299