10

Beginner JavaScript question. I'm sort of spoiled on the dir built-in function from Python. I want to discover the properties/methods of any object in the node.js REPL. I have already seen this question; the accepted answer fails (in the node REPL) in the simple case of an empty array []. For example:

for(var prop in []){console.log(prop);}  # returns undefined, prints nothing
[].length  # returns 0

Since the for loop does not discover the array's length method, I do not consider that to be proper introspection. So, could someone fill in the blank here:

function magic(some_object) {
  # magic goes here
}

console.log(magic([]))  # should print a list that includes 'length'

Or is this simply not possible, or only possible for "user types"?

Community
  • 1
  • 1
wberry
  • 18,519
  • 8
  • 53
  • 85
  • You can use tab completion in the REPL FYI and it works fairly well to see most things, but a complete answer to your question is fairly complicated. Mostly what you want can be achieved but it requires a fairly large bag of tricks. `util.inspect` and `console.log` in node are also handy, and I wrote my own `util.inspect` implementation at one point which I will post once I find it if an answer hasn't been accepted by then. – Peter Lyons Jul 18 '13 at 20:33

1 Answers1

11

How far back do you need to go in browser compatibility? All of the modern browsers should support Object.getOwnPropertyNames(). Using your example, Object.getOwnPropertyNames([]) will return ["length"].

More info here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames

Edit: Other examples:

  • Object.getOwnPropertyNames([1, 2, 3]); returns ["0", "1", "2", "length"]

  • Object.getOwnPropertyNames(String); returns ["prototype", "quote", "substring", "toLowerCase", "toUpperCase", "charAt", "charCodeAt", "contains", "indexOf", "lastIndexOf", "startsWith", "endsWith", "trim", "trimLeft", "trimRight", "toLocaleLowerCase", "toLocaleUpperCase", "localeCompare", "match", "search", "replace", "split", "substr", "concat", "slice", "fromCharCode", "length", "name", "arguments", "caller"]

Edit #2: Okay, so seeing that you are looking for complete list of properties and methods, including inherited ones, I've borrowed from two other SO questions (linked below) and come up with a solution that appears to get you even closer:

var findProperties = function(obj) {
    var aPropertiesAndMethods = [];

    do {
        aPropertiesAndMethods = aPropertiesAndMethods.concat(Object.getOwnPropertyNames(obj));
    } while (obj = Object.getPrototypeOf(obj));

    for ( var a = 0; a < aPropertiesAndMethods.length; ++a) {
        for ( var b = a + 1; b < aPropertiesAndMethods.length; ++b) {
            if (aPropertiesAndMethods[a] === aPropertiesAndMethods[b]) {
                aPropertiesAndMethods.splice(a--, 1);
            }
        }
    }

    return aPropertiesAndMethods;
}

So if you use call findProperties([]), it returns ["length", "join", "reverse", "sort", "push", "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "iterator", "constructor", "toSource", "toString", "toLocaleString", "valueOf", "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__"]

Linked Questions

javascript inheritance, reflection and prototype chain walking?

How to merge two arrays in Javascript and de-duplicate items

Community
  • 1
  • 1
talemyn
  • 7,822
  • 4
  • 31
  • 52
  • 2
    Well, I'm in `node` not a browser, but this is in the right direction. Still not giving me everything though. `Object.getOwnPropertyNames([])` returns `[ 'length' ]`, though an empty array also has a `.toString()` method. And `Object.getOwnPropertyNames(Array)` provides more methods (including `prototype`) but still not `toString`. You get my upvote but I'd still like to programmatically get *all* the properties/methods that are valid if I can. – wberry Jul 19 '13 at 02:46
  • 1
    Okay, so you are not only looking for the properties and methods of the actual object, but the ones that it inherits as well? Because, technically, `toString` is a method of `Object.prototype` and that is simply inherited by `Array`. Not sure if there is any way to grab the inherited methods and properties as well . . . – talemyn Jul 19 '13 at 15:28
  • 1
    Aha I think I'm learning here. So I could write a function that follows the inheritance tree up to `Object` and builds a set of everything it finds? I don't see an obvious way to do that. `Object.getPrototypeOf([])` just returns `[]` not `Array`. – wberry Jul 19 '13 at 16:00
  • 1
    Funny you should ask . . . while you were typing that, I was writing that very function. :D Special thanks to some of the answers in the two threads that I linked for pointing me in the right direction. – talemyn Jul 19 '13 at 16:06
  • 1
    Oh, and I added it to my answer, if that was not clear. LOL – talemyn Jul 19 '13 at 16:14
  • 1
    Your `findProperties` function appears to be exactly what I'm looking for. It shows me that `[]` has `push`, `toString`, etc. and that functions have `call` and `apply` properties. It still doesn't work for some things (`null`, `undefined`, `2`, `''`) but I assume that is because those things are not really considered to be objects and don't have properties anyway. For example while it doesn't work for `''` it does work for `new String('')` which is considered different. – wberry Jul 19 '13 at 16:59
  • 3
    You can get a return for `2` if you make it a defined `Number` object (i.e., `console.log(findProperties(new Number(2)));`). Interestingly, it gives you a different result than `console.log(findProperties(Number));`, showing the difference between an object (e.g., `Number`) and an instance of an object (e.g. `2`). – talemyn Jul 19 '13 at 17:07
  • 1
    I upvoted this years ago. I wish I could upvote it again because I use it all the time! – Mark McClure Apr 14 '18 at 13:34
  • 1
    @MarkMcClure - Glad it helped! Honestly, it's probably the most interesting conversation that I've ever had on SO. :D – talemyn Apr 16 '18 at 17:42