function getAllPropertyNames(
    obj, includeObjectPrototype = undefined,
    includeFunctionPrototype = undefined) {
  if (!obj) {
    return [];
  }

  // Naively use a for..in loop to get the property names if the browser doesn't
  // support any other APIs for getting it.
  if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) {
    return getKeys(obj);
  }

  const visitedSet = {};

  // Traverse the prototype chain and add all properties to the visited set.
  let proto = obj;
  while (proto && (proto !== Object.prototype || !!includeObjectPrototype) &&
         (proto !== Function.prototype || !!includeFunctionPrototype)) {
    const names = Object.getOwnPropertyNames(proto);
    for (let i = 0; i < names.length; i++) {
      visitedSet[names[i]] = true;
    }
    proto = Object.getPrototypeOf(proto);
  }

  return getKeys(visitedSet);
}
Get all properties names on a given Object regardless of enumerability.
<p> If the browser does not support `Object.getOwnPropertyNames` nor
`Object.getPrototypeOf` then this is equivalent to using
`getKeys`
@param {?Object} obj The object to get the properties of.
@param {boolean=} includeObjectPrototype Whether properties defined on
    `Object.prototype` should be included in the result.
@param {boolean=} includeFunctionPrototype Whether properties defined on
    `Function.prototype` should be included in the result.
@return {!Array<string>}
@public