【问题标题】:How to distinguish between property that is not enumerable and ES6 methods如何区分不可枚举的属性和 ES6 方法
【发布时间】:2021-01-15 14:17:12
【问题描述】:

我想创建一个返回对象所有属性的函数:

这是我的初始代码:

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

我有 ES6 类,我想在其中隐藏一些属性:

    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() {
        }
        ...
    }

我遇到的问题是 Object.getOwnPropertyNames 返回可枚举属性,而 Object.key 不返回 ES6 类方法。所以我如果使用第一个函数,我会得到隐藏的道具,如果我使用第二个函数,我只会得到__input__

有没有办法检测某些东西是否是隐藏属性而不是 ES6 类方法?我不想检测某个东西是否是函数,因为我想要更通用的东西,因为不能有作为函数的可枚举属性。

我还发现,对于 ES5 构造函数,有一个构造函数属性也是不可枚举的,其行为类似于 ES6 方法(在我的 Lexer 类的情况下,它使用相同的标记方法)。

注意:这不是 Y/X 问题我想为我的 Scheme 解释器创建 dir 函数,它可以像 Python 中的类似函数一样工作,它应该与 ES5 函数构造函数对象和 ES6 类对象一起工作。

我试过这个:

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));
}

但我不知道这是否是最好的方法,因为用户可能想要创建原型的属性描述符(我不确定这是否可能发生)。我想要 100% 的工作解决方案而不是解决方法。你知道有什么方法可以让它工作吗?

编辑:

即使我有适合我的情况的有效解决方案,我想知道 ES6 属性实际上是否与不可枚举的属性无法区分。

特别是如果您可以检测到 foo 是否与 bar 不同:

class Test {
  constructor() {

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

唯一的区别是 bar 在原型对象上,没有其他方法可以检测到区别吗?

【问题讨论】:

  • @Teemu 是的,我已经用我尝试过的方法编辑了问题,但我不确定这是否是最好的方法。
  • @Teemu 这不起作用,任何提示如何使用它?所有方法都有描述符,说明该方法不可枚举。因此,据我所知,无法区分方法和隐藏属性描述符。
  • 我的错,我没有意识到getOwnPropertyNames 也返回了不可枚举的属性,使用基本上与您在示例中已有的相同,只是迭代一个对象而不是一个数组。
  • @Teemu 您的解决方案可能会更快,因为它一次返回所有描述符。
  • Scheme 中的对象模型是什么?方案代码甚至会知道原型继承吗?

标签: javascript ecmascript-6


【解决方案1】:

有没有办法检测某些东西是否是隐藏属性而不是 ES6 类方法?我不想检测某个东西是否是函数

没有区别。类方法只是原型对象的不可枚举的函数值属性。

如果你一定要区分它们,你可以.toString() 函数并检查它是否有方法语法,但这仍然不会捕获被复制的方法并错过 ES5 方法。 (相关主题另见How do you check the difference between an ECMAScript 6 class and function?How can I differentiate between an arrow function, class and a normal function?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-10
    • 2013-09-03
    • 1970-01-01
    • 2013-01-08
    • 2012-05-03
    • 2022-01-09
    • 1970-01-01
    • 2010-11-09
    相关资源
    最近更新 更多