Search code examples
javascriptnode.jsintrospection

JavaScript introspection that is complete


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"?


Solution

  • 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