【问题标题】:Get array of class's properties without instantiating it?获取类的属性数组而不实例化它?
【发布时间】:2022-05-16 21:01:14
【问题描述】:

您似乎应该能够做到这一点,因为如果逻辑可以与类无关地编写,则基于类定义 (Angular) 动态构建表单会工作得更好。这将是可扩展的,因此向类添加字段也不需要更新生成表单和模板的逻辑。

有没有办法做到这一点,甚至有一个 NPM 模块可以做到这一点?

我发现我可以做到ClassName.toString(),但解析它会很痛苦。如果不出意外,我可能会编写一个模块来完成它。

我只是觉得为了枚举其属性而实例化该类的一个虚拟实例是一种糟糕的策略。

【问题讨论】:

  • 这就是 JavaScript 的工作原理。没有类,只有函数、对象和原型。对象的属性可以在其构造函数中定义。给定function Test() { this.prop = 3 }; x = new Test(),你怎么知道xprop 属性而不运行构造函数?

标签: javascript npm


【解决方案1】:

你可以使用Object.getOwnPropertyNames()

示例类:

class Foo { setBar() { throw Error('not implemented'); return false; } getBar() { throw Error('not implemented'); return false; } }

然后

Object.getOwnPropertyNames(Foo.prototype)

结果

["constructor", "setBar", "getBar"]

当我研究这个时,我首先查看了Object.keys,虽然它不起作用,但您可能希望参考the documentation for Object.keys's polyfill。它具有用于剥离 constructortoString 等的代码,以及正确实现 hasOwnProperty 的代码。

另见Bergi's answer here

【讨论】:

    【解决方案2】:

    任何方式?将您的类声明为函数,并将属性放在原型上:

    var Presidents = function() {
    };
    
    Presidents.prototype = {
      "washington" : "george",
      "adams" : "john"
    }
    
    console.log(Object.keys(Presidents.prototype))
    
    // Output is
    //  [ 'washington', 'adams' ]
    

    【讨论】:

    • class 已经是一个函数,它的方法原型上。
    • 你只是要告诉我我错了,而不告诉我正确的表达方式吗?太冷了。
    • 我没有说你错了,我只是指出class presidentsfunction presidents是一回事。
    • 啊,我们正在使用特定的关键字,是吗?那我换个说法:你只是要指出说了一些在这种情况下完全没有意义的事情,而没有告诉我a更明智的说法?这不友好
    • 我的评论中没有任何部分是不友好的,而且我当然不必排成一列来评论或批评您的答案。
    【解决方案3】:

    getOwnPropertyDescriptors 的类原型只会暴露方法和访问器描述符 - 没有实例化就无法确定数据属性(也因为构造函数参数会影响 props 的数量、类型和值)。不想实例化可能有几个原因(例如,因为一些静态计数器跟踪实例) - 因此一种解决方法可能是动态创建类的副本并将该“影子”与示例构造函数参数一起实例化。

        /**
         * get properties from class definition without instantiating it
         *
         * @param cls: class
         * @param args: sample arguments to pass to shadow constructor
         * @usage `const props = getInstanceProperties(MyClass);`
         * @notice this will regex replace the classname (can be an issue with strings containing that substring)
         */
        const getInstanceProperties = (cls, args = [], ignore = ['constructor', 'toString']) => {
            const className = cls.prototype.constructor.name;
            const shadowCode = cls.toString().replace(new RegExp(`${className}`, 'g'), `_${className}_`);
            const shadowClass = eval(`(${shadowCode})`);
            const o = new shadowClass(...args);
            const methodsAndAccessors = Object.getOwnPropertyDescriptors(cls.prototype);
            const dataDescriptors = Object.getOwnPropertyDescriptors(o);
            const descriptors = Object.assign({}, methodsAndAccessors, dataDescriptors);
            ignore.forEach(name => delete descriptors[name]);
            return descriptors;
        };
    
    
        class Foo extends Object {
          static instances = 0;
          #myPrivateVar = 123;
          myValue=123;
          constructor(){
              super();
              this.myConstructorVar = ++Foo.instances;
          }
          myMethod() {}
          set myAccessor(x){}
        }
    
        console.log(Object.keys(getInstanceProperties(Foo)));

    将返回: [ 'myMethod', 'myAccessor', 'myValue', 'myConstructorProp' ]

    【讨论】:

      猜你喜欢
      • 2015-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-14
      • 2022-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多