135

In JavaScript we have a few ways of getting the properties of an object, depending on what we want to get.

1) Object.keys(), which returns all own, enumerable properties of an object, an ECMA5 method.

2) a for...in loop, which returns all the enumerable properties of an object, regardless of whether they are own properties, or inherited from the prototype chain.

3) Object.getOwnPropertyNames(obj) which returns all own properties of an object, enumerable or not.

We also have such methods as hasOwnProperty(prop) lets us check if a property is inherited or actually belongs to that object, and propertyIsEnumerable(prop) which, as the name suggests, lets us check if a property is enumerable.

With all these options, there is no way to get a non-enumerable, non-own property of an object, which is what I want to do. Is there any way to do this? In other words, can I somehow get a list of the inherited non-enumerable properties?

Thank you.

2
  • 5
    Your question answered the question I was going to ask: How to inspect non-enumerable properties (just to explore what is available in predefined objects). Finally I found getOwnPropertyNames! :-)
    – marcus
    Commented Dec 16, 2011 at 19:30
  • 1
    @marcus :-) That's what SO is all about!
    – dkugappi
    Commented Dec 21, 2011 at 16:14

11 Answers 11

150

Since getOwnPropertyNames can get you non-enumerable properties, you can use that and combine it with walking up the prototype chain.

function getAllProperties(obj){
    var allProps = []
      , curr = obj
    do{
        var props = Object.getOwnPropertyNames(curr)
        props.forEach(function(prop){
            if (allProps.indexOf(prop) === -1)
                allProps.push(prop)
        })
    }while(curr = Object.getPrototypeOf(curr))
    return allProps
}

console.log(getAllProperties([1,2,3]));

I tested that on Safari 5.1 and got

> getAllProperties([1,2,3])
["0", "1", "2", "length", "constructor", "push", "slice", "indexOf", "sort", "splice", "concat", "pop", "unshift", "shift", "join", "toString", "forEach", "reduceRight", "toLocaleString", "some", "map", "lastIndexOf", "reduce", "filter", "reverse", "every", "hasOwnProperty", "isPrototypeOf", "valueOf", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "propertyIsEnumerable", "__lookupSetter__"]

Update: Refactored the code a bit (added spaces, and curly braces, and improved the function name):

function getAllPropertyNames(obj) {
  var props = [];

  do {
    Object.getOwnPropertyNames(obj).forEach(function (prop) {
      if (props.indexOf(prop) === -1) {
        props.push(prop);
      }
    });

    obj = Object.getPrototypeOf(obj);
  } while (obj);

  return props;
}
14
  • 1
    Thanks toby, one thing I don't understand is the line: while(curr = Object.getPrototypeOf(cure)), as the conditional statement uses an assignment operator instead of a comparison operator, wouldn't this always return true? Or is this line essentially checking whether "curr" has a prototype?
    – dkugappi
    Commented Nov 6, 2011 at 1:05
  • 2
    @AlexNabokov it will return false if the result is falsy, which will occur when Object.getPrototypeOf(cure) returns null at the top of the prototype chain. I guess this assumes no circular prototype chains!
    – Domenic
    Commented Nov 6, 2011 at 3:07
  • 2
    @Alex Function.prototype can never be the "root" prototype, since it's prototype link points to Object.prototype. The function Object.getPrototypeOf( obj ) returns the topmost object in the prototype chain of obj. It enables you to follow the prototype chain of obj until you reach its end (the null value). I'm not sure what your issue with this is... Commented Nov 7, 2011 at 14:01
  • 2
    @Alex No, it's not undefined. Object.getPrototypeOf(John) returns the Boy.prototype object (as it should) - see here: jsfiddle.net/aeGLA/1. Note that the constructor Boy is not in the prototype chain of John. The prototype chain of John is as follows: Boy.prototype -> Object.prototype -> null. Commented Nov 7, 2011 at 14:13
  • 3
    "I thought Object.getPrototypeOf(obj) will return the obj's constructor's prototype" - Yes. In the case of John, his constructor is Boy, and the prototype property of Boy is Boy.prototype. So Object.getPrototypeOf(John) returns Boy.prototype. Commented Nov 7, 2011 at 14:18
20

A cleaner solution using recursion:

function getAllPropertyNames (obj) {
    const proto     = Object.getPrototypeOf(obj);
    const inherited = (proto) ? getAllPropertyNames(proto) : [];
    return [...new Set(Object.getOwnPropertyNames(obj).concat(inherited))];
}

Edit

More generic functions:

function walkProtoChain (obj, callback) {
    const proto     = Object.getPrototypeOf(obj);
    const inherited = (proto) ? walkProtoChain(proto, callback) : [];
    return [...new Set(callback(obj).concat(inherited))];
}

function getOwnNonEnumPropertyNames (obj) {
    return Object.getOwnPropertyNames(obj)
        .filter(p => !obj.propertyIsEnumerable(p));
}

function getAllPropertyNames (obj) {
    return walkProtoChain(obj, Object.getOwnPropertyNames);
}

function getAllEnumPropertyNames (obj) {
    return walkProtoChain(obj, Object.keys);
}

function getAllNonEnumPropertyNames (obj) {
    return walkProtoChain(obj, getOwnNonEnumPropertyNames);
}

This same template can be applied using Object.getOwnPropertySymbols, etc.

0
16

Update Jan 2022 -- almost every answer combined, plus symbols (ES6+)

After seeing Mozilla's JS documentation specifically say: "no single mechanism iterates all of an object's properties; the various mechanisms each include different subsets of properties."... I had exactly this question albeit newer because I want symbol keys also and I think all the answers above pre-date those).

I came here hoping someone else knew how to create such a single mechanism.

No single answer on this page seems to cover EVERYTHING, but between all of them, I think it can be done -- including the option to also exclude the annoying top level keys.

In exploring the code in Mozilla's JS doc'n that airportyh's answer inspired, plus the table below it on that same page I discovered the new Reflect.ownKeys. That catches everything (including symbols)... except inherited properties, but airportyh's answer walking the prototype chain fixes that.

So... combining all those findings and simplifying as much as I could, I came up with the following two functions, that (I believe) DO catch EVERYTHING. Posting in case it helps anyone else.

Option 1. Simple: Return EVERY Key, no exceptions

Returns every key, enumerable or not, string, symbol, own, inherited, and top level.

function getAllKeys(obj) {
    let keys = [];
    // if primitive (primitives still have keys) skip the first iteration
    if (!(obj instanceof Object)) {
        obj = Object.getPrototypeOf(obj)
    }
    while (obj) {
        keys = keys.concat(Reflect.ownKeys(obj));
        obj = Object.getPrototypeOf(obj);
    }
    return keys;
}

I really like the simplicity, though I wonder if I've missed anything. If any one catches any errors in that, please do let me know.

Option 2. Flexible: Return EVERY Key, with optional exclusions

Adds:

  1. a filter function based on a bunch of one line functions (easier to debug that way, and this ain't code golf 😉) that determine if any given key should be excluded, based on the parameters passed in,
  2. a condition to walk the prototype chain or not (per airportyh's answer), and,
  3. a condition to stop or not before the top level is reached (per Maciej Krawczyk's answer).

Include or exclude:

  • enumerable keys
  • non-enumerable keys
  • symbol keys
  • string keys
  • own keys
  • inherited keys
  • top level keys.

(On a side note, I'm no JS expert, so maybe I'm missing something. I'm a little confused why no one else here has used Array.prototype.filter(), since isn't that exactly what we're doing?)

I believe the following covers it. By default everything is included except top level keys. Adjust to taste. Again I'd welcome feedback if any errors here:

function getAllKeysConditionally(obj, includeSelf = true, includePrototypeChain = true, includeTop = false, includeEnumerables = true, includeNonenumerables = true, includeStrings = true, includeSymbols = true) {
    
    // Boolean (mini-)functions to determine any given key's eligibility:
    const isEnumerable = (obj, key) => Object.propertyIsEnumerable.call(obj, key);
    const isString = (key) => typeof key === 'string';
    const isSymbol = (key) => typeof key === 'symbol';
    const includeBasedOnEnumerability = (obj, key) => (includeEnumerables && isEnumerable(obj, key)) || (includeNonenumerables && !isEnumerable(obj, key));
    const includeBasedOnKeyType = (key) => (includeStrings && isString(key)) || (includeSymbols && isSymbol(key));
    const include = (obj, key) => includeBasedOnEnumerability(obj, key) && includeBasedOnKeyType(key);
    const notYetRetrieved = (keys, key) => !keys.includes(key);
    
    // filter function putting all the above together:
    const filterFn = key => notYetRetrieved(keys, key) && include(obj, key);
    
    // conditional chooses one of two functions to determine whether to exclude the top level or not:
    const stopFn = includeTop ? (obj => obj === null) : (obj => Object.getPrototypeOf(obj) === null);
    
    // and now the loop to collect and filter everything:
    let keys = [];
    while (!stopFn(obj, includeTop)) {
        if (includeSelf) {
            const ownKeys = Reflect.ownKeys(obj).filter(filterFn);
            keys = keys.concat(ownKeys);
        }
        if (!includePrototypeChain) { break; }
        else {
            includeSelf = true;
            obj = Object.getPrototypeOf(obj);
        }
    }
    return keys;
}

As noted by Jeff Hykin in the comments these solutions use Reflect and arrow functions which are new in ES6. Therefore ES6 minimum required.

6
  • 1
    Criminally underrated answer (1 other upvote as of writing). Should probably add an Ecmascript version warning though (e.g. when does it stop working: ES5/ES6/ES7)
    – Jeff Hykin
    Commented Feb 6, 2022 at 14:55
  • @JeffHykin, Thanks! (for the feedback, and the edit). Admittedly, I'm not certain what you mean by your "when does it stop working" point. I think you mean "what's the earliest version of ES that it works in (whereas it fails in any version previous to that)"...? I think the newest functionality it uses is the Reflect.ownKeys(), but I can't seem to find anything on when that was introduced. I'd welcome any assistance with this.
    – DavidT
    Commented Mar 15, 2022 at 0:44
  • 1
    Welcome! And yes, my comment should say "when does it start working". Reflect is from ES6, and I'm confident thats the only version-dependent feature for getAllKeys. For the getAllKeysConditionally, arrow functions are also ES6 and default values are ES5. So overall this should work for ES6 and newer 👍
    – Jeff Hykin
    Commented Mar 16, 2022 at 13:15
  • 1
    Thanks for the welcome and the info! 😊 Added ES6+ to the heading, and a note at the end.
    – DavidT
    Commented Mar 23, 2022 at 6:13
  • 1
    A-- Good point (duplicate keys), with sets as the solution, although what if I want ALL keys, somehow, even the duplicates (ie. I want some record of the duplicates, though I'm not sure what would be the appropriate representation of that)? I can think of a couple of ideas to solve that, but now getting even more beyond the scope of the original question. 😊 B. Yes, fair enough. C. Fair enough again. Apologies, I missed your use of filter. 😊
    – DavidT
    Commented Aug 22, 2022 at 19:46
5

Straight forward iterative in ES6:

function getAllPropertyNames(obj) {
    let result = new Set();
    while (obj) {
        Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
        obj = Object.getPrototypeOf(obj);
    }
    return [...result];
}

Example run:

function getAllPropertyNames(obj) {
  let result = new Set();
  while (obj) {
    Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
    obj = Object.getPrototypeOf(obj);
  }
  return [...result];
}

let obj = {
  abc: 123,
  xyz: 1.234,
  foobar: "hello"
};

console.log(getAllPropertyNames(obj));

4

Taking advantage of Sets leads to a somewhat cleaner solution, IMO.

const own = Object.getOwnPropertyNames;
const proto = Object.getPrototypeOf;

function getAllPropertyNames(obj) {
    const props = new Set();
    do own(obj).forEach(p => props.add(p)); while (obj = proto(obj));
    return Array.from(props);
}
2

if you are trying to log non enumerable properties of a parent object ex. by default the methods defined inside a class in es6 are set on prototype but are set as non-enumerable.

Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
2

You usually don't want to include Object prototype properties such as __defineGetter__, hasOwnProperty, __proto__ and so on.

This implementation allows you to either include or exclude Object prototype properties:

function getAllPropertyNames(object, includeObjectPrototype = false) {
  const props = Object.getOwnPropertyNames(object);

  let proto = Object.getPrototypeOf(object);
  const objectProto = Object.getPrototypeOf({});

  while (proto && (includeObjectPrototype || proto !== objectProto)) {
    for (const prop of Object.getOwnPropertyNames(proto)) {
      if (props.indexOf(prop) === -1) {
        props.push(prop);
      }
    }
    proto = Object.getPrototypeOf(proto);
  }

  return props;
}

console.log(getAllPropertyNames(new Error('Test'), true));
// ["fileName", "lineNumber", "columnNumber", "message", "toString", "name", "stack", "constructor", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "__proto__"]
console.log(getAllPropertyNames(new Error('Test'), false));
// [ "fileName", "lineNumber", "columnNumber", "message", "toString", "name", "stack", "constructor" ]
1

To get all inherited properties or methods for some instance you could use something like this

var BaseType = function () {
    this.baseAttribute = "base attribute";
    this.baseMethod = function() {
        return "base method";
    };
};

var SomeType = function() {
    BaseType();
    this.someAttribute = "some attribute";
    this.someMethod = function (){
        return "some method";
    };
};

SomeType.prototype = new BaseType();
SomeType.prototype.constructor = SomeType;

var instance = new SomeType();

Object.prototype.getInherited = function(){
    var props = []
    for (var name in this) {  
        if (!this.hasOwnProperty(name) && !(name == 'constructor' || name == 'getInherited')) {  
            props.push(name);
        }  
    }
    return props;
};

alert(instance.getInherited().join(","));
4
  • 1
    Better to use Object.getInherited rather than Object.prototype.getInherited. Doing that also removes the need for the ugly !(name == 'getInherited') check. Also, in your implementation, the props array can contain duplicate properties. Lastly, what's the purpose of ignoring the constructor property?
    – Pauan
    Commented Jul 17, 2013 at 12:35
  • When will object.getInherited will become true? Please check below question as I am stuck with inheritance: stackoverflow.com/questions/31718345/… Commented Jul 31, 2015 at 8:26
  • IMHO - these belong to Reflect, not to Object. Or - alternatively - I'd expect from the language Object.keys(src, [settings]) where optional settings can specify if to include non-ninumerables, if to include inheritted, if to include non-enumerable inheritted, if to include own, if to include symbols, and perhaps to what max inheritance depth to dig. Commented Apr 27, 2020 at 6:32
  • uh... same for Object.entries. Not sure about Object.values though. ...well. why not. Commented Apr 27, 2020 at 6:42
0

Here is the solution that I came up with while studying the subject. To get all non-enumerable non-own properties of the obj object do getProperties(obj, "nonown", "nonenum");

function getProperties(obj, type, enumerability) {
/**
 * Return array of object properties
 * @param {String} type - Property type. Can be "own", "nonown" or "both"
 * @param {String} enumerability - Property enumerability. Can be "enum", 
 * "nonenum" or "both"
 * @returns {String|Array} Array of properties
 */
    var props = Object.create(null);  // Dictionary

    var firstIteration = true;

    do {
        var allProps = Object.getOwnPropertyNames(obj);
        var enumProps = Object.keys(obj);
        var nonenumProps = allProps.filter(x => !(new Set(enumProps)).has(x));

        enumProps.forEach(function(prop) {
            if (!(prop in props)) {
                props[prop] = { own: firstIteration, enum_: true };
            }           
        });

        nonenumProps.forEach(function(prop) {
            if (!(prop in props)) {
                props[prop] = { own: firstIteration, enum_: false };
            }           
        });

        firstIteration = false;
    } while (obj = Object.getPrototypeOf(obj));

    for (prop in props) {
        if (type == "own" && props[prop]["own"] == false) {
            delete props[prop];
            continue;
        }
        if (type == "nonown" && props[prop]["own"] == true) {
            delete props[prop];
            continue;
        }

        if (enumerability == "enum" && props[prop]["enum_"] == false) {
            delete props[prop];
            continue;
        }
        if (enumerability == "nonenum" && props[prop]["enum_"] == true) {
            delete props[prop];
        }
    }

    return Object.keys(props);
}
0
function getNonEnumerableNonOwnPropertyNames( obj ) {
    var oCurObjPrototype = Object.getPrototypeOf(obj);
    var arReturn = [];
    var arCurObjPropertyNames = [];
    var arCurNonEnumerable = [];
    while (oCurObjPrototype) {
        arCurObjPropertyNames = Object.getOwnPropertyNames(oCurObjPrototype);
        arCurNonEnumerable = arCurObjPropertyNames.filter(function(item, i, arr){
            return !oCurObjPrototype.propertyIsEnumerable(item);
        })
        Array.prototype.push.apply(arReturn,arCurNonEnumerable);
        oCurObjPrototype = Object.getPrototypeOf(oCurObjPrototype);
    }
    return arReturn;
}

Example of using:

function MakeA(){

}

var a = new MakeA();

var arNonEnumerable = getNonEnumerableNonOwnPropertyNames(a);
0

An implementation in my personal preferences :)

function getAllProperties(In, Out = {}) {
    const keys = Object.getOwnPropertyNames(In);
    keys.forEach(key => Object.defineProperty(In, key, {
        enumerable: true
    }));
    Out = { ...In, ...Out };

    const Prototype = Object.getPrototypeOf(In);
    return Prototype === Object.prototype ? Out : getAllProperties(Proto, Out);
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.