0

I want to create function that will return all properties of an object:

This is my initial code:

function dir(obj) {
   if (obj === null || obj === Object.prototype) {
      return [];
   }
   var names = Object.getOwnPropertyNames(obj);
   return names.concat(dir(Object.getPrototypeOf(obj)));
}

and I have ES6 class where I want to hide some properties:

    class Lexer {
        constructor(input, { whitespace = false } = {}) {
            this.__input__ = input.replace(/\r/g, '');
            var internals = {};
            [
                '_i', '_whitespace', '_col', '_newline', '_line',
                '_state', '_next', '_token', '_prev_char'
            ].forEach(name => {
                Object.defineProperty(this, name, {
                    configurable: false,
                    enumerable: false,
                    get() {
                        return internals[name];
                    },
                    set(value) {
                        internals[name] = value;
                    }
                });
            });
            this._whitespace = whitespace;
            this._i = this._line = this._col = this._newline = 0;
            this._state = this._next = this._token = null;
            this._prev_char = '';
        }
        token() {
        }
        ...
    }

The problem I have is that Object.getOwnPropertyNames return enumerable properties and Object.key don't return ES6 class methods. So I if Use the first function I get hidden props and if I use second I only get __input__.

Is there a way to detect if something is hidden property and not ES6 class method? I don't want to detect if something is a function because I want something more generic there can be not enumerable properties that are functions.

I've also found that for ES5 constructor function there is constructor property that is also not enumerable and behave like ES6 method (in case of my Lexer class it work the same token method).

NOTE: this is not Y/X problem I want to create dir function for my Scheme interpreter that will work like similar function in Python, it should work with ES5 function constructor objects and ES6 class objects.

I've tried this:

function dir(obj, proto) {
   if (obj === null || obj === Object.prototype) {
      return [];
   }
   var names = Object.getOwnPropertyNames(obj);
   if (!proto) {
      names = names.filter(name => {
        var d = Object.getOwnPropertyDescriptor(obj, name);
        return d.configurable && d.enumerable;
      });
   }
   return names.concat(dir(Object.getPrototypeOf(obj), true));
}

but I don't know if this is the best way, since the user may want to create property descriptor of prototype (i'm not sure if this is something that may happen). I want 100% working solution and not work around. Do you know any method to make it work?

EDIT:

Even that I have working solution for my case, I'm wondering if ES6 properties in fact are indistinguishable from not enunumerable properties.

Especially if you can detect if foo is different then bar:

class Test {
  constructor() {

    Object.defineProperty(this, 'foo', {
      enumerable: false,
      configurable: false,
      value: function() { alert('foo') }
    });
  }
  bar() {
    alert('bar');
  }
}

Is the only difference is that bar is on prototype object and there are no other way to detect the difference?

jcubic
  • 61,973
  • 54
  • 229
  • 402
  • @Teemu yes, I've edited the question with what I've tried but I'm not sure if this is the best way. – jcubic Jan 15 '21 at 14:20
  • @Teemu This don't work, any hints how to use it? All methods have descriptor that say that method is not enumerable. So from what I see there is no way to distinguish method from hidden property descriptor. – jcubic Jan 15 '21 at 14:38
  • My bad, I didn't realize `getOwnPropertyNames` returns the non-enumerable properties too, the use is essentially the same you already have in your example, just iterating an object instead of an array. – Teemu Jan 15 '21 at 14:41
  • @Teemu your solution may be faster because it return all descriptors at onces. – jcubic Jan 15 '21 at 14:45
  • What's your object model in Scheme? Will the scheme code even know about prototype inheritance? – Bergi Jan 15 '21 at 15:06
  • @Bergi the code in my Scheme look almost the same like in JavaScript it only have different syntax (prefix notation) so my dir function look almost the same in my Scheme. – jcubic Jan 15 '21 at 15:12
  • @Bergi if you're interested here is my dir in Scheme https://github.com/jcubic/lips/blob/devel/lib/bootstrap.scm#L365 – jcubic Jan 15 '21 at 15:14
  • @jcubic Ah I thought Scheme would have its own data types and object model which the interpreter would need to emulate, but you're essentially just executing javascript with a special syntax. – Bergi Jan 15 '21 at 15:19
  • "*I want to hide some properties*" - depending on your security requirements, I would recommend to just hide underscore-prefixed names from `dir`, use symbols, or maybe an approach similar to [`Symbol.unscopables`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/unscopables) – Bergi Jan 15 '21 at 15:23
  • Btw, that extra `internals` object looks unnecessary. Unless you want to distinguish your properties by virtue of being getters/setters, you should just keep writable data properties directly on your instances, and make these non-enumerable and non-configurable. Should be more performant as well. – Bergi Jan 15 '21 at 15:25

1 Answers1

3

Is there a way to detect if something is hidden property and not ES6 class method? I don't want to detect if something is a function

There's no distinction. A class method is just a non-enumerable function-valued property of the prototype object.

If you absolutely had to distinguish them, you could .toString() the function and check whether it has method syntax, but that still won't catch methods that are copied around and miss ES5 methods. (See also How do you check the difference between an ECMAScript 6 class and function? and How can I differentiate between an arrow function, class and a normal function? for related topics)

Bergi
  • 630,263
  • 148
  • 957
  • 1,375