Task

The goal is to get the methods of an object, as names, values or both.

Some languages offer dynamic methods, which in general can only be inspected if a class' public API includes a way of listing them.

// Sample classes for reflection
function Super(name) {
    this.name = name;
    this.superOwn = function() { return 'super owned'; };
}
Super.prototype = {
    constructor: Super
    className: 'super',
    toString: function() { return "Super(" + this.name + ")"; },
    doSup: function() { return 'did super stuff'; }
}
 
function Sub() {
    Object.getPrototypeOf(this).constructor.apply(this, arguments);
    this.rest = [].slice.call(arguments, 1);
    this.subOwn = function() { return 'sub owned'; };
}
Sub.prototype = Object.assign(
    new Super('prototype'),
    {
        constructor: Sub
        className: 'sub',
        toString: function() { return "Sub(" + this.name + ")"; },
        doSub: function() { return 'did sub stuff'; }
    });
 
Object.defineProperty(Sub.prototype, 'shush', {
    value: function() { return ' non-enumerable'; },
    enumerable: false // the default
});
 
var sup = new Super('sup'),
    sub = new Sub('sub', 0, 'I', 'two');
 
Object.defineProperty(sub, 'quiet', {
    value: function() { return 'sub owned non-enumerable'; },
    enumerable: false
});
 
// get enumerable methods on an object and its ancestors
function get_method_names(obj) {
    var methods = [];
    for (var p in obj) {
        if (typeof obj[p] == 'function') {
            methods.push(p);
        }
    }
    return methods;
}
 
get_method_names(sub);
//["subOwn", "superOwn", "toString", "doSub", "doSup"]
 
// get enumerable properties on an object and its ancestors
function get_property_names(obj) {
    var properties = [];
    for (var p in obj) {
        properties.push(p);
    }
    return properties;
}
 
// alternate way to get enumerable method names on an object and its ancestors
function get_method_names(obj) {
    return get_property_names(obj)
        .filter(function(p) {return typeof obj[p] == 'function';});
}
 
get_method_names(sub);
//["subOwn", "superOwn", "toString", "doSub", "doSup"]
 
// get enumerable & non-enumerable method names set directly on an object
Object.getOwnPropertyNames(sub)
    .filter(function(p) {return typeof sub[p] == 'function';})
//["subOwn", "shhh"]
 
// get enumerable method names set directly on an object
Object.keys(sub)
    .filter(function(p) {return typeof sub[p] == 'function';})
//["subOwn"]
 
// get enumerable method names & values set directly on an object
Object.entries(sub)
    .filter(function(p) {return typeof p[1] == 'function';})
//[["subOwn", function () {...}]]